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:
Pavel V. Talanov
2014-06-10 16:50:35 +04:00
parent 07935c837a
commit db5303c019
82 changed files with 1813 additions and 527 deletions
@@ -36,7 +36,7 @@ import org.jetbrains.jet.lang.resolve.name.FqName;
* <p/>
* See {@link LineBreakpoint#findClassCandidatesInSourceContent} for the primary usage this was introduced
*/
/* package */ class FakeLightClassForFileOfPackage extends AbstractLightClass implements KotlinLightClass, JetJavaMirrorMarker {
public class FakeLightClassForFileOfPackage extends AbstractLightClass implements KotlinLightClass, JetJavaMirrorMarker {
private final KotlinLightClassForPackage delegate;
private final JetFile file;
@@ -34,7 +34,9 @@ import com.intellij.util.SmartList;
import com.intellij.util.containers.SLRUCache;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetEnumEntry;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.java.JavaPsiFacadeKotlinHacks;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.kotlin.PackagePartClassUtils;
@@ -141,17 +143,21 @@ public class JavaElementFinder extends PsiElementFinder implements JavaPsiFacade
}
private void findPackageClass(FqName qualifiedName, GlobalSearchScope scope, List<PsiClass> answer) {
Collection<JetFile> filesForPackage = lightClassGenerationSupport.findFilesForPackage(qualifiedName, scope);
if (PackagePartClassUtils.getPackageFilesWithCallables(filesForPackage).isEmpty()) return;
List<LightClassGenerationSupport.KotlinLightPackageClassInfo>
packageClassesInfos = lightClassGenerationSupport.findPackageClassesInfos(qualifiedName, scope);
for (LightClassGenerationSupport.KotlinLightPackageClassInfo info : packageClassesInfos) {
Collection<JetFile> files = info.getFiles();
if (PackagePartClassUtils.getPackageFilesWithCallables(files).isEmpty()) continue;
KotlinLightClassForPackage lightClass =
KotlinLightClassForPackage.create(psiManager, qualifiedName, info.getScope(), files);
if (lightClass == null) continue;
KotlinLightClassForPackage lightClass = KotlinLightClassForPackage.create(psiManager, qualifiedName, scope, filesForPackage);
if (lightClass == null) return;
answer.add(lightClass);
answer.add(lightClass);
if (filesForPackage.size() > 1) {
for (JetFile file : filesForPackage) {
answer.add(new FakeLightClassForFileOfPackage(psiManager, lightClass, file));
if (files.size() > 1) {
for (JetFile file : files) {
answer.add(new FakeLightClassForFileOfPackage(psiManager, lightClass, file));
}
}
}
}
@@ -35,6 +35,7 @@ import com.intellij.util.containers.SLRUCache;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.ReadOnly;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
@@ -424,4 +425,11 @@ public class KotlinLightClassForPackage extends KotlinWrappingLightClass impleme
return KotlinLightClassForPackage.class.getSimpleName() + ":" + e.toString();
}
}
//NOTE: this is only needed to compute plugin module info
@NotNull
@ReadOnly
public final Collection<JetFile> getFiles() {
return files;
}
}
@@ -27,6 +27,7 @@ import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.name.FqName;
import java.util.Collection;
import java.util.List;
public abstract class LightClassGenerationSupport {
@@ -54,6 +55,12 @@ public abstract class LightClassGenerationSupport {
@NotNull
public abstract Collection<JetFile> findFilesForPackage(@NotNull FqName fqName, @NotNull GlobalSearchScope searchScope);
@NotNull
public abstract List<KotlinLightPackageClassInfo> findPackageClassesInfos(
@NotNull FqName fqName,
@NotNull GlobalSearchScope wholeScope
);
// Returns only immediately declared classes/objects, package classes are not included (they have no declarations)
@NotNull
public abstract Collection<JetClassOrObject> findClassOrObjectDeclarationsInPackage(
@@ -68,4 +75,24 @@ public abstract class LightClassGenerationSupport {
@Nullable
public abstract PsiClass getPsiClass(@NotNull JetClassOrObject classOrObject);
public final class KotlinLightPackageClassInfo {
private final Collection<JetFile> files;
private final GlobalSearchScope scope;
public KotlinLightPackageClassInfo(@NotNull Collection<JetFile> files, @NotNull GlobalSearchScope scope) {
this.files = files;
this.scope = scope;
}
@NotNull
public Collection<JetFile> getFiles() {
return files;
}
@NotNull
public GlobalSearchScope getScope() {
return scope;
}
}
}
@@ -32,9 +32,18 @@ import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory.*
import org.jetbrains.jet.lang.psi.JetParameter
import org.jetbrains.jet.lang.psi.JetClass
import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory
import org.jetbrains.jet.lang.psi.JetClassObject
public fun getJvmSignatureDiagnostics(element: PsiElement, otherDiagnostics: Diagnostics): Diagnostics? {
public fun getJvmSignatureDiagnostics(element: PsiElement, otherDiagnostics: Diagnostics, moduleScope: GlobalSearchScope): Diagnostics? {
fun getDiagnosticsForPackage(file: JetFile): Diagnostics? {
val project = file.getProject()
val cache = KotlinLightClassForPackage.FileStubCache.getInstance(project)
return cache[file.getPackageFqName(), moduleScope].getValue()?.extraDiagnostics
}
fun getDiagnosticsForClass(jetClassOrObject: JetClassOrObject): Diagnostics {
return KotlinLightClassForExplicitDeclaration.getLightClassData(jetClassOrObject).extraDiagnostics
}
fun doGetDiagnostics(): Diagnostics? {
var parent = element.getParent()
if (element is JetPropertyAccessor) {
@@ -134,13 +143,3 @@ private fun ConflictingJvmDeclarationsData.higherThan(other: ConflictingJvmDecla
else -> false
}
}
private fun getDiagnosticsForPackage(file: JetFile): Diagnostics? {
val project = file.getProject()
val cache = KotlinLightClassForPackage.FileStubCache.getInstance(project)
return cache[file.getPackageFqName(), GlobalSearchScope.allScope(project)].getValue()?.extraDiagnostics
}
private fun getDiagnosticsForClass(jetClassOrObject: JetClassOrObject): Diagnostics {
return KotlinLightClassForExplicitDeclaration.getLightClassData(jetClassOrObject).extraDiagnostics
}