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:
+60
-12
@@ -24,6 +24,8 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import kotlin.Function1;
|
||||
import kotlin.KotlinPackage;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.asJava.KotlinLightClassForExplicitDeclaration;
|
||||
@@ -65,20 +67,10 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
|
||||
|
||||
public IDELightClassGenerationSupport(@NotNull Project project) {
|
||||
this.project = project;
|
||||
final GlobalSearchScope searchScope = GlobalSearchScope.allScope(project);
|
||||
this.jetFileComparator = new Comparator<JetFile>() {
|
||||
@Override
|
||||
public int compare(@NotNull JetFile o1, @NotNull JetFile o2) {
|
||||
VirtualFile f1 = o1.getVirtualFile();
|
||||
VirtualFile f2 = o2.getVirtualFile();
|
||||
if (f1 == f2) return 0;
|
||||
if (f1 == null) return -1;
|
||||
if (f2 == null) return 1;
|
||||
return searchScope.compare(f1, f2);
|
||||
}
|
||||
};
|
||||
this.jetFileComparator = byScopeComparator(GlobalSearchScope.allScope(project));
|
||||
}
|
||||
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public LightClassConstructionContext getContextForPackage(@NotNull Collection<JetFile> files) {
|
||||
@@ -169,6 +161,47 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
|
||||
return PackageIndexUtil.findFilesWithExactPackage(fqName, kotlinSources(searchScope, project), project);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<KotlinLightPackageClassInfo> findPackageClassesInfos(
|
||||
@NotNull FqName fqName, @NotNull GlobalSearchScope wholeScope
|
||||
) {
|
||||
Collection<JetFile> allFiles = findFilesForPackage(fqName, wholeScope);
|
||||
Map<IdeaModuleInfo, List<JetFile>> filesByInfo = groupByModuleInfo(allFiles);
|
||||
List<KotlinLightPackageClassInfo> result = new ArrayList<KotlinLightPackageClassInfo>();
|
||||
for (Map.Entry<IdeaModuleInfo, List<JetFile>> entry : filesByInfo.entrySet()) {
|
||||
result.add(new KotlinLightPackageClassInfo(entry.getValue(), entry.getKey().contentScope()));
|
||||
}
|
||||
sortByClasspath(wholeScope, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Map<IdeaModuleInfo, List<JetFile>> groupByModuleInfo(@NotNull Collection<JetFile> allFiles) {
|
||||
return KotlinPackage.groupByTo(
|
||||
allFiles,
|
||||
new LinkedHashMap<IdeaModuleInfo, List<JetFile>>(),
|
||||
new Function1<JetFile, IdeaModuleInfo>() {
|
||||
@Override
|
||||
public IdeaModuleInfo invoke(JetFile file) {
|
||||
return ResolvePackage.getModuleInfo(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void sortByClasspath(@NotNull GlobalSearchScope wholeScope, @NotNull List<KotlinLightPackageClassInfo> result) {
|
||||
final Comparator<JetFile> byScopeComparator = byScopeComparator(wholeScope);
|
||||
Collections.sort(result, new Comparator<KotlinLightPackageClassInfo>() {
|
||||
@Override
|
||||
public int compare(@NotNull KotlinLightPackageClassInfo info1, @NotNull KotlinLightPackageClassInfo info2) {
|
||||
JetFile file1 = info1.getFiles().iterator().next();
|
||||
JetFile file2 = info2.getFiles().iterator().next();
|
||||
//classes earlier that would appear earlier on classpath should go first
|
||||
return -byScopeComparator.compare(file1, file2);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<JetClassOrObject> findClassOrObjectDeclarationsInPackage(
|
||||
@@ -211,4 +244,19 @@ public class IDELightClassGenerationSupport extends LightClassGenerationSupport
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static Comparator<JetFile> byScopeComparator(@NotNull final GlobalSearchScope searchScope) {
|
||||
return new Comparator<JetFile>() {
|
||||
@Override
|
||||
public int compare(@NotNull JetFile o1, @NotNull JetFile o2) {
|
||||
VirtualFile f1 = o1.getVirtualFile();
|
||||
VirtualFile f2 = o2.getVirtualFile();
|
||||
if (f1 == f2) return 0;
|
||||
if (f1 == null) return -1;
|
||||
if (f2 == null) return 1;
|
||||
return searchScope.compare(f1, f2);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* 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.plugin.caches.resolve
|
||||
|
||||
import org.jetbrains.jet.analyzer.ModuleInfo
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.OrderEntry
|
||||
import com.intellij.openapi.roots.ModuleSourceOrderEntry
|
||||
import com.intellij.openapi.roots.ModuleOrderEntry
|
||||
import com.intellij.openapi.roots.LibraryOrderEntry
|
||||
import com.intellij.openapi.roots.JdkOrderEntry
|
||||
import com.intellij.openapi.module.Module
|
||||
import org.jetbrains.jet.lang.resolve.name.Name
|
||||
import java.util.LinkedHashSet
|
||||
import com.intellij.openapi.roots.ModuleRootManager
|
||||
import com.intellij.openapi.roots.libraries.Library
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.module.impl.scopes.LibraryScopeBase
|
||||
import com.intellij.openapi.roots.OrderRootType
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.jet.utils.emptyOrSingletonList
|
||||
|
||||
private abstract class IdeaModuleInfo : ModuleInfo {
|
||||
abstract fun contentScope(): GlobalSearchScope
|
||||
}
|
||||
|
||||
private fun orderEntryToModuleInfo(project: Project, orderEntry: OrderEntry): List<IdeaModuleInfo> {
|
||||
return when (orderEntry) {
|
||||
is ModuleSourceOrderEntry -> {
|
||||
listOf(orderEntry.getOwnerModule().toSourceInfo())
|
||||
}
|
||||
is ModuleOrderEntry -> {
|
||||
emptyOrSingletonList(orderEntry.getModule()?.toSourceInfo())
|
||||
}
|
||||
is LibraryOrderEntry -> {
|
||||
val library = orderEntry.getLibrary() ?: return listOf()
|
||||
emptyOrSingletonList(LibraryInfo(project, library))
|
||||
}
|
||||
is JdkOrderEntry -> {
|
||||
val sdk = orderEntry.getJdk() ?: return listOf()
|
||||
emptyOrSingletonList(SdkInfo(project, sdk))
|
||||
}
|
||||
else -> {
|
||||
throw IllegalStateException("Unexpected order entry $orderEntry")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: (module refactoring) there should be separate ModuleTestInfo
|
||||
private data class ModuleSourceInfo(val module: Module) : IdeaModuleInfo() {
|
||||
override val name = Name.special("<sources for module ${module.getName()}>")
|
||||
|
||||
override fun contentScope() = GlobalSearchScope.moduleScope(module)
|
||||
|
||||
override fun dependencies(): List<IdeaModuleInfo> {
|
||||
//NOTE: lib dependencies can be processed several times during recursive traversal
|
||||
val result = LinkedHashSet<IdeaModuleInfo>()
|
||||
ModuleRootManager.getInstance(module).orderEntries().compileOnly().recursively().exportedOnly().forEach {
|
||||
orderEntry ->
|
||||
result.addAll(orderEntryToModuleInfo(module.getProject(), orderEntry!!))
|
||||
true
|
||||
}
|
||||
return result.toList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun Module.toSourceInfo() = ModuleSourceInfo(this)
|
||||
|
||||
private data class LibraryInfo(val project: Project, val library: Library) : IdeaModuleInfo() {
|
||||
override val name: Name = Name.special("<library ${library.getName()}>")
|
||||
|
||||
override fun contentScope() = LibraryWithoutSourceScope(project, library)
|
||||
|
||||
override fun dependencies(): List<IdeaModuleInfo> {
|
||||
//TODO: (module refactoring) heuristic dependencies for libraries
|
||||
val orderEntry = ModuleManager.getInstance(project).getModules().stream().flatMap {
|
||||
ModuleRootManager.getInstance(it).getOrderEntries().stream()
|
||||
}.firstOrNull { it is JdkOrderEntry } as? JdkOrderEntry
|
||||
val sdk = orderEntry?.getJdk()
|
||||
return if (sdk != null) listOf(SdkInfo(project, sdk), this) else listOf(this)
|
||||
}
|
||||
}
|
||||
|
||||
private data class LibrarySourceInfo(val project: Project, val library: Library) : IdeaModuleInfo() {
|
||||
override val name: Name = Name.special("<sources for library ${library.getName()}>")
|
||||
|
||||
override fun contentScope() = GlobalSearchScope.EMPTY_SCOPE
|
||||
|
||||
override fun dependencies(): List<IdeaModuleInfo> {
|
||||
return listOf(this) + LibraryInfo(project, library).dependencies()
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: (module refactoring) there should be separate SdkSourceInfo but there are no kotlin source in existing sdks for now :)
|
||||
private data class SdkInfo(val project: Project, val sdk: Sdk) : IdeaModuleInfo() {
|
||||
override val name: Name = Name.special("<library ${sdk.getName()}>")
|
||||
|
||||
override fun contentScope() = SdkScope(project, sdk)
|
||||
|
||||
override fun dependencies(): List<IdeaModuleInfo> = listOf(this)
|
||||
}
|
||||
|
||||
private object NotUnderContentRootModuleInfo : IdeaModuleInfo() {
|
||||
override val name: Name = Name.special("<special module for files not under source root>")
|
||||
|
||||
override fun contentScope() = GlobalSearchScope.EMPTY_SCOPE
|
||||
|
||||
//TODO: (module refactoring) dependency on runtime can be of use here
|
||||
override fun dependencies(): List<IdeaModuleInfo> = listOf(this)
|
||||
}
|
||||
|
||||
private data class LibraryWithoutSourceScope(project: Project, private val library: Library) :
|
||||
LibraryScopeBase(project, library.getFiles(OrderRootType.CLASSES), array<VirtualFile>()) {
|
||||
}
|
||||
|
||||
//TODO: (module refactoring) android sdk has modified scope
|
||||
private data class SdkScope(project: Project, private val sdk: Sdk) :
|
||||
LibraryScopeBase(project, sdk.getRootProvider().getFiles(OrderRootType.CLASSES), array<VirtualFile>())
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.plugin.caches.resolve
|
||||
|
||||
import org.jetbrains.jet.plugin.project.TargetPlatform
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmResolverForModule
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||
|
||||
public object JavaResolveExtension : CacheExtension<(PsiElement) -> Pair<JavaDescriptorResolver, BindingContext>> {
|
||||
override val platform: TargetPlatform = TargetPlatform.JVM
|
||||
|
||||
override fun getData(resolverProvider: ModuleResolverProvider): (PsiElement) -> Pair<JavaDescriptorResolver, BindingContext> {
|
||||
return {
|
||||
val resolverForModule = resolverProvider.resolverByModule(it.getModuleInfo()) as JvmResolverForModule
|
||||
Pair(resolverForModule.javaDescriptorResolver, resolverForModule.lazyResolveSession.getBindingContext())
|
||||
}
|
||||
}
|
||||
|
||||
public fun getResolver(project: Project, element: PsiElement): JavaDescriptorResolver =
|
||||
KotlinCacheService.getInstance(project)[this](element).first
|
||||
|
||||
public fun getContext(project: Project, element: PsiElement): BindingContext =
|
||||
KotlinCacheService.getInstance(project)[this](element).second
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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.plugin.caches.resolve
|
||||
|
||||
import org.jetbrains.jet.lang.resolve.lazy.ResolveSession
|
||||
import org.jetbrains.jet.analyzer.ResolverForModule
|
||||
import org.jetbrains.jet.lang.psi.JetFile
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.jet.analyzer.PlatformAnalysisParameters
|
||||
import org.jetbrains.jet.analyzer.AnalyzerFacade
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.jet.context.GlobalContext
|
||||
import org.jetbrains.jet.analyzer.ResolverForProject
|
||||
import org.jetbrains.k2js.analyze.AnalyzerFacadeForJS
|
||||
import org.jetbrains.jet.lang.PlatformToKotlinClassMap
|
||||
import org.jetbrains.jet.lang.resolve.lazy.declarations.DeclarationProviderFactoryService
|
||||
import org.jetbrains.jet.lang.resolve.BindingTraceContext
|
||||
import org.jetbrains.jet.di.InjectorForLazyResolve
|
||||
import org.jetbrains.jet.lang.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.jet.analyzer.ModuleInfo
|
||||
import org.jetbrains.jet.analyzer.ModuleContent
|
||||
|
||||
public class JsResolverForModule(
|
||||
override val lazyResolveSession: ResolveSession
|
||||
) : ResolverForModule
|
||||
|
||||
|
||||
public object JsAnalyzerFacade : AnalyzerFacade<JsResolverForModule, PlatformAnalysisParameters> {
|
||||
|
||||
override fun <M : ModuleInfo> createResolverForModule(
|
||||
project: Project,
|
||||
globalContext: GlobalContext,
|
||||
moduleDescriptor: ModuleDescriptorImpl,
|
||||
moduleContent: ModuleContent,
|
||||
platformParameters: PlatformAnalysisParameters,
|
||||
resolverForProject: ResolverForProject<M, JsResolverForModule>
|
||||
): JsResolverForModule {
|
||||
val (syntheticFiles, moduleContentScope) = moduleContent
|
||||
val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory(
|
||||
project, globalContext.storageManager, syntheticFiles, moduleContentScope
|
||||
)
|
||||
|
||||
val injector = InjectorForLazyResolve(project, globalContext, moduleDescriptor, declarationProviderFactory, BindingTraceContext())
|
||||
val resolveSession = injector.getResolveSession()!!
|
||||
moduleDescriptor.initialize(resolveSession.getPackageFragmentProvider())
|
||||
return JsResolverForModule(resolveSession)
|
||||
}
|
||||
|
||||
override val defaultImports = AnalyzerFacadeForJS.DEFAULT_IMPORTS
|
||||
override val platformToKotlinClassMap = PlatformToKotlinClassMap.EMPTY
|
||||
|
||||
}
|
||||
+16
-18
@@ -33,7 +33,12 @@ import org.jetbrains.jet.plugin.project.TargetPlatform.*
|
||||
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
|
||||
import org.jetbrains.jet.plugin.project.TargetPlatformDetector
|
||||
import org.jetbrains.jet.lang.psi.JetCodeFragment
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils
|
||||
import org.jetbrains.jet.context.GlobalContext
|
||||
import org.jetbrains.jet.plugin.stubindex.JetSourceFilterScope
|
||||
import com.intellij.psi.PsiElement
|
||||
|
||||
private val LOG = Logger.getInstance(javaClass<KotlinCacheService>())
|
||||
|
||||
@@ -41,10 +46,6 @@ public fun JetElement.getLazyResolveSession(): ResolveSessionForBodies {
|
||||
return KotlinCacheService.getInstance(getProject()).getLazyResolveSession(this)
|
||||
}
|
||||
|
||||
public fun Project.getLazyResolveSession(platform: TargetPlatform): ResolveSessionForBodies {
|
||||
return KotlinCacheService.getInstance(this).getGlobalLazyResolveSession(platform)
|
||||
}
|
||||
|
||||
public fun JetElement.getAnalysisResults(): AnalyzeExhaust {
|
||||
return KotlinCacheService.getInstance(getProject()).getAnalysisResults(listOf(this))
|
||||
}
|
||||
@@ -64,19 +65,16 @@ public class KotlinCacheService(val project: Project) {
|
||||
public fun getInstance(project: Project): KotlinCacheService = ServiceManager.getService(project, javaClass<KotlinCacheService>())!!
|
||||
}
|
||||
|
||||
private fun globalResolveSessionProvider(platform: TargetPlatform, syntheticFiles: Collection<JetFile> = listOf()) = {
|
||||
val setup = AnalyzerFacadeProvider.getAnalyzerFacade(platform)
|
||||
.createSetup(project, syntheticFiles, GlobalSearchScope.allScope(project))
|
||||
val resolveSessionForBodies = ResolveSessionForBodies(project, setup.getLazyResolveSession())
|
||||
private fun globalResolveSessionProvider(platform: TargetPlatform, syntheticFiles: Collection<JetFile> = listOf()):
|
||||
() -> CachedValueProvider.Result<ModuleResolverProvider> = {
|
||||
val analyzerFacade = AnalyzerFacadeProvider.getAnalyzerFacade(platform)
|
||||
val moduleMapping = createModuleResolverProvider(project, analyzerFacade, syntheticFiles)
|
||||
CachedValueProvider.Result.create(
|
||||
SessionAndSetup(
|
||||
platform,
|
||||
resolveSessionForBodies,
|
||||
setup
|
||||
),
|
||||
moduleMapping,
|
||||
PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT,
|
||||
resolveSessionForBodies
|
||||
moduleMapping.exceptionTracker
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
private val globalCachesPerPlatform = mapOf(
|
||||
@@ -102,17 +100,17 @@ public class KotlinCacheService(val project: Project) {
|
||||
}
|
||||
}
|
||||
|
||||
public fun getGlobalLazyResolveSession(platform: TargetPlatform): ResolveSessionForBodies {
|
||||
return globalCachesPerPlatform[platform]!!.getLazyResolveSession()
|
||||
public fun getGlobalLazyResolveSession(file: JetFile, platform: TargetPlatform): ResolveSessionForBodies {
|
||||
return globalCachesPerPlatform[platform]!!.getLazyResolveSession(file)
|
||||
}
|
||||
|
||||
public fun getLazyResolveSession(element: JetElement): ResolveSessionForBodies {
|
||||
val file = element.getContainingJetFile()
|
||||
if (!isFileInScope(file)) {
|
||||
return getCacheForSyntheticFile(file).getLazyResolveSession()
|
||||
return getCacheForSyntheticFile(file).getLazyResolveSession(file)
|
||||
}
|
||||
|
||||
return getGlobalLazyResolveSession(TargetPlatformDetector.getPlatform(file))
|
||||
return getGlobalLazyResolveSession(file, TargetPlatformDetector.getPlatform(file))
|
||||
}
|
||||
|
||||
public fun getAnalysisResults(elements: Collection<JetElement>): AnalyzeExhaust {
|
||||
|
||||
+17
-23
@@ -38,7 +38,6 @@ import com.intellij.openapi.roots.libraries.LibraryUtil
|
||||
import org.jetbrains.jet.lang.resolve.LibrarySourceHacks
|
||||
import org.jetbrains.jet.plugin.project.TargetPlatform
|
||||
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
|
||||
import org.jetbrains.jet.analyzer.AnalyzerFacade
|
||||
import java.util.HashMap
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||
@@ -64,43 +63,37 @@ import org.jetbrains.jet.analyzer.analyzeInContext
|
||||
import org.jetbrains.jet.lang.resolve.BindingTraceContext
|
||||
import org.jetbrains.jet.lang.types.TypeUtils
|
||||
import org.jetbrains.jet.lang.resolve.scopes.ChainedScope
|
||||
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor
|
||||
|
||||
public trait CacheExtension<T> {
|
||||
public val platform: TargetPlatform
|
||||
public fun getData(setup: AnalyzerFacade.Setup): T
|
||||
public fun getData(resolverProvider: ModuleResolverProvider): T
|
||||
}
|
||||
|
||||
private class SessionAndSetup(
|
||||
val platform: TargetPlatform,
|
||||
val resolveSessionForBodies: ResolveSessionForBodies,
|
||||
val setup: AnalyzerFacade.Setup
|
||||
)
|
||||
|
||||
private class KotlinResolveCache(
|
||||
val project: Project,
|
||||
setupProvider: () -> CachedValueProvider.Result<SessionAndSetup>
|
||||
setupProvider: () -> CachedValueProvider.Result<ModuleResolverProvider>
|
||||
) {
|
||||
|
||||
private val setupCache = SynchronizedCachedValue(project, setupProvider, trackValue = false)
|
||||
private val resolverCache = SynchronizedCachedValue(project, setupProvider, trackValue = false)
|
||||
|
||||
public fun getLazyResolveSession(): ResolveSessionForBodies = setupCache.getValue().resolveSessionForBodies
|
||||
|
||||
public fun <T> get(extension: CacheExtension<T>): T {
|
||||
val sessionAndSetup = setupCache.getValue()
|
||||
assert(extension.platform == sessionAndSetup.platform,
|
||||
"Extension $extension declares platfrom ${extension.platform} which is incompatible with ${sessionAndSetup.platform}")
|
||||
return extension.getData(sessionAndSetup.setup)
|
||||
public fun getLazyResolveSession(element: JetElement): ResolveSessionForBodies {
|
||||
return resolverCache.getValue().resolveSessionForBodiesByModule(element.getModuleInfo())
|
||||
}
|
||||
|
||||
private val analysisResults = CachedValuesManager.getManager(project).createCachedValue ({
|
||||
val resolveSession = getLazyResolveSession()
|
||||
public fun <T> get(extension: CacheExtension<T>): T {
|
||||
return extension.getData(resolverCache.getValue())
|
||||
}
|
||||
|
||||
private val analysisResults = CachedValuesManager.getManager(project).createCachedValue(
|
||||
{
|
||||
val resolverProvider = resolverCache.getValue()
|
||||
val results = object : SLRUCache<JetFile, PerFileAnalysisCache>(2, 3) {
|
||||
override fun createValue(file: JetFile?): PerFileAnalysisCache {
|
||||
return PerFileAnalysisCache(file!!, resolveSession)
|
||||
return PerFileAnalysisCache(file!!, resolverProvider.resolveSessionForBodiesByModule(file.getModuleInfo()))
|
||||
}
|
||||
}
|
||||
|
||||
CachedValueProvider.Result(results, PsiModificationTracker.MODIFICATION_COUNT, resolveSession.getExceptionTracker())
|
||||
CachedValueProvider.Result(results, PsiModificationTracker.MODIFICATION_COUNT, resolverProvider.exceptionTracker)
|
||||
}, false)
|
||||
|
||||
fun getAnalysisResultsForElements(elements: Collection<JetElement>): AnalyzeExhaust {
|
||||
@@ -118,7 +111,8 @@ private class KotlinResolveCache(
|
||||
return if (error != null)
|
||||
AnalyzeExhaust.error(bindingContext, error.getError())
|
||||
else
|
||||
AnalyzeExhaust.success(bindingContext, getLazyResolveSession().getModuleDescriptor())
|
||||
//TODO: (module refactoring) several elements are passed here in debugger
|
||||
AnalyzeExhaust.success(bindingContext, getLazyResolveSession(elements.first()).getModuleDescriptor())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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.plugin.caches.resolve
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.jet.context.GlobalContext
|
||||
import com.intellij.openapi.roots.ModuleRootManager
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import org.jetbrains.jet.utils.keysToMap
|
||||
import com.intellij.openapi.roots.LibraryOrderEntry
|
||||
import org.jetbrains.jet.plugin.project.ResolveSessionForBodies
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmPlatformParameters
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.impl.JavaClassImpl
|
||||
import com.intellij.openapi.roots.JdkOrderEntry
|
||||
import org.jetbrains.kotlin.util.sure
|
||||
import org.jetbrains.jet.analyzer.AnalyzerFacade
|
||||
import org.jetbrains.jet.analyzer.ResolverForModule
|
||||
import org.jetbrains.jet.lang.psi.*
|
||||
import org.jetbrains.jet.storage.ExceptionTracker
|
||||
import org.jetbrains.jet.lang.resolve.java.structure.JavaClass
|
||||
import org.jetbrains.jet.analyzer.ResolverForProject
|
||||
import org.jetbrains.jet.analyzer.ModuleContent
|
||||
import org.jetbrains.jet.analyzer.PlatformAnalysisParameters
|
||||
import org.jetbrains.jet.plugin.caches.resolve
|
||||
|
||||
fun createModuleResolverProvider(
|
||||
project: Project,
|
||||
analyzerFacade: AnalyzerFacade<ResolverForModule, JvmPlatformParameters>,
|
||||
syntheticFiles: Collection<JetFile>
|
||||
): ModuleResolverProvider {
|
||||
|
||||
val allModuleInfos = collectAllModuleInfosFromIdeaModel(project).toHashSet()
|
||||
|
||||
val globalContext = GlobalContext()
|
||||
|
||||
fun createResolverForProject(): ResolverForProject<IdeaModuleInfo, ResolverForModule> {
|
||||
val syntheticFilesByModule = syntheticFiles.groupBy { it.getModuleInfo() }
|
||||
allModuleInfos.addAll(syntheticFilesByModule.keySet())
|
||||
|
||||
val modulesContent = {(module: IdeaModuleInfo) ->
|
||||
ModuleContent(syntheticFilesByModule[module] ?: listOf(), module.contentScope())
|
||||
}
|
||||
|
||||
val jvmPlatformParameters = JvmPlatformParameters {
|
||||
(javaClass: JavaClass) ->
|
||||
val psiClass = (javaClass as JavaClassImpl).getPsi()
|
||||
psiClass.getModuleInfo()
|
||||
}
|
||||
|
||||
val resolverForProject = analyzerFacade.setupResolverForProject(
|
||||
globalContext, project, allModuleInfos, modulesContent, jvmPlatformParameters
|
||||
)
|
||||
return resolverForProject
|
||||
}
|
||||
|
||||
val resolverForProject = createResolverForProject()
|
||||
|
||||
val moduleToBodiesResolveSession = allModuleInfos.keysToMap {
|
||||
module ->
|
||||
val analyzer = resolverForProject.resolverForModule(module)
|
||||
ResolveSessionForBodies(project, analyzer.lazyResolveSession)
|
||||
}
|
||||
return ModuleResolverProvider(
|
||||
resolverForProject,
|
||||
moduleToBodiesResolveSession,
|
||||
globalContext.exceptionTracker
|
||||
)
|
||||
}
|
||||
|
||||
private fun collectAllModuleInfosFromIdeaModel(project: Project): List<IdeaModuleInfo> {
|
||||
val ideaModules = ModuleManager.getInstance(project).getModules().toList()
|
||||
val modulesSourcesInfos = ideaModules.map { it.toSourceInfo() }
|
||||
|
||||
//TODO: (module refactoring) include libraries that are not among dependencies of any module
|
||||
val ideaLibraries = ideaModules.flatMap {
|
||||
ModuleRootManager.getInstance(it).getOrderEntries().filterIsInstance(javaClass<LibraryOrderEntry>()).map {
|
||||
it.getLibrary()
|
||||
}
|
||||
}.filterNotNull().toSet()
|
||||
|
||||
val librariesInfos = ideaLibraries.map { LibraryInfo(project, it) }
|
||||
|
||||
val ideaSdks = ideaModules.flatMap {
|
||||
ModuleRootManager.getInstance(it).getOrderEntries().filterIsInstance(javaClass<JdkOrderEntry>()).map {
|
||||
it.getJdk()
|
||||
}
|
||||
}.filterNotNull().toSet()
|
||||
|
||||
val sdksInfos = ideaSdks.map { SdkInfo(project, it) }
|
||||
|
||||
val collectAllModuleInfos = modulesSourcesInfos + librariesInfos + sdksInfos
|
||||
return collectAllModuleInfos
|
||||
}
|
||||
|
||||
class ModuleResolverProvider(
|
||||
private val resolverForProject: ResolverForProject<IdeaModuleInfo, *>,
|
||||
private val bodiesResolveByModule: Map<IdeaModuleInfo, ResolveSessionForBodies>,
|
||||
val exceptionTracker: ExceptionTracker
|
||||
) {
|
||||
fun resolverByModule(module: IdeaModuleInfo): ResolverForModule = resolverForProject.resolverForModule(module)
|
||||
|
||||
fun resolveSessionForBodiesByModule(module: IdeaModuleInfo) =
|
||||
//NOTE: if this assert fails in production, additional information can be obtained by logging on the call site
|
||||
bodiesResolveByModule[module] ?: throw AssertionError("Requested data for $module not contained in this resolver.")
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.plugin.caches.resolve
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.jet.lang.resolve.java.jetAsJava.KotlinLightElement
|
||||
import org.jetbrains.jet.lang.psi.*
|
||||
import com.intellij.openapi.roots.ProjectFileIndex
|
||||
import com.intellij.openapi.roots.LibraryOrSdkOrderEntry
|
||||
import com.intellij.openapi.roots.LibraryOrderEntry
|
||||
import com.intellij.openapi.roots.JdkOrderEntry
|
||||
import org.jetbrains.jet.asJava.FakeLightClassForFileOfPackage
|
||||
import org.jetbrains.jet.asJava.KotlinLightClassForPackage
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
|
||||
fun PsiElement.getModuleInfo(): IdeaModuleInfo {
|
||||
fun logAndReturnDefault(message: String): IdeaModuleInfo {
|
||||
LOG.error("Could not find correct module information.\nReason: $message")
|
||||
return NotUnderContentRootModuleInfo
|
||||
}
|
||||
|
||||
if (this is KotlinLightElement<*, *>)
|
||||
return this.getModuleInfoForLightElement()
|
||||
|
||||
if (this is JetCodeFragment)
|
||||
return this.getContext()?.getModuleInfo()
|
||||
?: logAndReturnDefault("Analyzing code fragment of type $javaClass with no context element\nText:\n${getText()}")
|
||||
|
||||
val containingJetFile = (this as? JetElement)?.getContainingFile() as? JetFile
|
||||
val context = containingJetFile?.analysisContext
|
||||
if (context != null) return context.getModuleInfo()
|
||||
|
||||
val doNotAnalyze = containingJetFile?.doNotAnalyze
|
||||
if (doNotAnalyze != null) {
|
||||
return logAndReturnDefault(
|
||||
"Should not analyze element: ${getText()} in file ${containingJetFile?.getName() ?: " <no file>"}\n$doNotAnalyze"
|
||||
)
|
||||
}
|
||||
|
||||
val project = getProject()
|
||||
val containingFile = getContainingFile()
|
||||
?: return logAndReturnDefault("Analyzing element of type $javaClass with no containing file\nText:\n${getText()}")
|
||||
|
||||
val virtualFile = containingFile.getOriginalFile().getVirtualFile()
|
||||
?: return logAndReturnDefault("Analyzing non-physical file $containingFile of type ${containingFile.javaClass}")
|
||||
|
||||
return getModuleInfoByVirtualFile(project, virtualFile)
|
||||
}
|
||||
|
||||
private fun getModuleInfoByVirtualFile(project: Project, virtualFile: VirtualFile): IdeaModuleInfo {
|
||||
val projectFileIndex = ProjectFileIndex.SERVICE.getInstance(project)
|
||||
|
||||
val module = projectFileIndex.getModuleForFile(virtualFile)
|
||||
if (module != null) return module.toSourceInfo()
|
||||
|
||||
val orderEntries = projectFileIndex.getOrderEntriesForFile(virtualFile)
|
||||
|
||||
val libraryOrSdkEntries = orderEntries.filterIsInstance(javaClass<LibraryOrSdkOrderEntry>())
|
||||
@entries for (libraryOrSdkOrderEntry in libraryOrSdkEntries) {
|
||||
when (libraryOrSdkOrderEntry) {
|
||||
is LibraryOrderEntry -> {
|
||||
val library = libraryOrSdkOrderEntry.getLibrary() ?: continue @entries
|
||||
if (projectFileIndex.isInLibrarySource(virtualFile)) {
|
||||
return LibrarySourceInfo(project, library)
|
||||
}
|
||||
else {
|
||||
return LibraryInfo(project, library)
|
||||
}
|
||||
}
|
||||
is JdkOrderEntry -> {
|
||||
val sdk = libraryOrSdkOrderEntry.getJdk() ?: continue @entries
|
||||
return SdkInfo(project, sdk)
|
||||
}
|
||||
}
|
||||
}
|
||||
return NotUnderContentRootModuleInfo
|
||||
}
|
||||
|
||||
private fun KotlinLightElement<*, *>.getModuleInfoForLightElement(): IdeaModuleInfo {
|
||||
val element = origin ?: when (this) {
|
||||
is FakeLightClassForFileOfPackage -> this.getContainingFile()!!
|
||||
is KotlinLightClassForPackage -> this.getFiles().first()
|
||||
else -> throw IllegalStateException("Unknown light class without origin is referenced by IDE lazy resolve: $javaClass")
|
||||
}
|
||||
return element.getModuleInfo()
|
||||
}
|
||||
+5
-1
@@ -20,6 +20,7 @@ import com.intellij.lang.annotation.AnnotationHolder;
|
||||
import com.intellij.lang.annotation.Annotator;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.asJava.AsJavaPackage;
|
||||
import org.jetbrains.jet.lang.psi.JetDeclaration;
|
||||
@@ -31,6 +32,8 @@ import org.jetbrains.jet.plugin.caches.resolve.ResolvePackage;
|
||||
import org.jetbrains.jet.plugin.project.TargetPlatform;
|
||||
import org.jetbrains.jet.plugin.project.TargetPlatformDetector;
|
||||
|
||||
import static org.jetbrains.jet.plugin.caches.resolve.ResolvePackage.getModuleInfo;
|
||||
|
||||
public class DuplicateJvmSignatureAnnotator implements Annotator {
|
||||
|
||||
@Override
|
||||
@@ -42,7 +45,8 @@ public class DuplicateJvmSignatureAnnotator implements Annotator {
|
||||
if (!(file instanceof JetFile) || TargetPlatformDetector.getPlatform((JetFile) file) != TargetPlatform.JVM) return;
|
||||
|
||||
Diagnostics otherDiagnostics = ResolvePackage.getBindingContext((JetElement) element).getDiagnostics();
|
||||
Diagnostics diagnostics = AsJavaPackage.getJvmSignatureDiagnostics(element, otherDiagnostics);
|
||||
GlobalSearchScope moduleScope = getModuleInfo(element).contentScope();
|
||||
Diagnostics diagnostics = AsJavaPackage.getJvmSignatureDiagnostics(element, otherDiagnostics, moduleScope);
|
||||
|
||||
if (diagnostics == null) return;
|
||||
JetPsiChecker.annotateElement(element, holder, diagnostics);
|
||||
|
||||
@@ -1,37 +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.plugin.project;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.analyzer.AnalyzerFacade;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.jet.lang.resolve.java.AnalyzerFacadeForJVM;
|
||||
|
||||
public final class AnalyzerFacadeProvider {
|
||||
private AnalyzerFacadeProvider() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static AnalyzerFacade getAnalyzerFacadeForFile(@NotNull JetFile file) {
|
||||
return getAnalyzerFacade(TargetPlatformDetector.getPlatform(file));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static AnalyzerFacade getAnalyzerFacade(@NotNull TargetPlatform targetPlatform) {
|
||||
return targetPlatform == TargetPlatform.JVM ? AnalyzerFacadeForJVM.INSTANCE : JSAnalyzerFacadeForIDEA.INSTANCE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.plugin.project
|
||||
|
||||
import org.jetbrains.jet.analyzer.AnalyzerFacade
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmPlatformParameters
|
||||
import org.jetbrains.jet.analyzer.ResolverForModule
|
||||
import org.jetbrains.jet.lang.resolve.java.JvmAnalyzerFacade
|
||||
import org.jetbrains.jet.plugin.caches.resolve.JsAnalyzerFacade
|
||||
|
||||
public object AnalyzerFacadeProvider {
|
||||
//NOTE: it's convenient that JS backend doesn't have platform parameters (for now)
|
||||
// otherwise we would be forced to add casts on the call site of setupResolverForProject
|
||||
public fun getAnalyzerFacade(targetPlatform: TargetPlatform): AnalyzerFacade<ResolverForModule, JvmPlatformParameters> {
|
||||
return when (targetPlatform) {
|
||||
TargetPlatform.JVM -> JvmAnalyzerFacade
|
||||
TargetPlatform.JS -> JsAnalyzerFacade
|
||||
else -> throw IllegalArgumentException("Unsupported platfrom: $targetPlatform")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +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.plugin.project;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.analyzer.AnalyzerFacade;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
import org.jetbrains.k2js.analyze.AnalyzerFacadeForJS;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public enum JSAnalyzerFacadeForIDEA implements AnalyzerFacade {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
private JSAnalyzerFacadeForIDEA() {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Setup createSetup(@NotNull Project project, @NotNull Collection<JetFile> syntheticFiles, @NotNull GlobalSearchScope filesScope) {
|
||||
return new BasicSetup(AnalyzerFacadeForJS.getLazyResolveSession(syntheticFiles, filesScope, new IDEAConfig(project)));
|
||||
}
|
||||
}
|
||||
@@ -21,12 +21,11 @@ import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.analyzer.AnalyzerFacade;
|
||||
import org.jetbrains.jet.lang.psi.JetFile;
|
||||
|
||||
public class TargetPlatformDetector {
|
||||
public static final TargetPlatformDetector INSTANCE = new TargetPlatformDetector();
|
||||
private static final Logger LOG = Logger.getInstance(AnalyzerFacade.class);
|
||||
private static final Logger LOG = Logger.getInstance(TargetPlatformDetector.class);
|
||||
|
||||
private TargetPlatformDetector() {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user