Improve diagnosticMissingPackageFragment reporting

Single execution path to report missing package fragment problems

Split failures on PluginDeclarationProviderFactory site by
known reasons to improve exception analysis
This commit is contained in:
Simon Ogorodnik
2017-10-27 22:48:40 +03:00
parent 56a51c1d22
commit 339d06d040
9 changed files with 103 additions and 39 deletions
@@ -153,8 +153,8 @@ class ReplCodeAnalyzer(environment: KotlinCoreEnvironment) {
return delegateFactory.getPackageMemberDeclarationProvider(packageFqName)
}
override fun diagnoseMissingPackageFragment(file: KtFile) {
delegateFactory.diagnoseMissingPackageFragment(file)
override fun diagnoseMissingPackageFragment(fqName: FqName, file: KtFile?) {
delegateFactory.diagnoseMissingPackageFragment(fqName, file)
}
class AdaptablePackageMemberDeclarationProvider(
@@ -55,12 +55,7 @@ class FileScopeFactory(
fun createScopesForFile(file: KtFile, existingImports: ImportingScope? = null): FileScopes {
val packageView = moduleDescriptor.getPackage(file.packageFqName)
val packageFragment = topLevelDescriptorProvider.getPackageFragment(file.packageFqName)
if (packageFragment == null) {
// TODO J2K and change return type of diagnoseMissingPackageFragment() to Nothing
(topLevelDescriptorProvider as? LazyClassContext)?.declarationProviderFactory?.diagnoseMissingPackageFragment(file)
error("Could not find fragment ${file.packageFqName} for file ${file.name}")
}
val packageFragment = topLevelDescriptorProvider.getPackageFragmentOrDiagnoseFailure(file.packageFqName, file)
return FilesScopesBuilder(file, existingImports, packageFragment, packageView).result
}
@@ -119,7 +114,7 @@ class FileScopeFactory(
}
}
val lexicalScope = LexicalScope.Base(lazyImportingScope, topLevelDescriptorProvider.getPackageFragment(file.packageFqName)!!)
val lexicalScope = LexicalScope.Base(lazyImportingScope, topLevelDescriptorProvider.getPackageFragmentOrDiagnoseFailure(file.packageFqName, file))
val importResolver = object : ImportResolver {
override fun forceResolveAllImports() {
@@ -216,16 +216,8 @@ open class LazyDeclarationResolver @Deprecated("") constructor(
val ktFile = declaration.containingFile as KtFile
val fqName = ktFile.packageFqName
topLevelDescriptorProvider.assertValid()
val packageDescriptor = topLevelDescriptorProvider.getPackageFragment(fqName)
if (packageDescriptor == null) {
if (topLevelDescriptorProvider is LazyClassContext) {
topLevelDescriptorProvider.declarationProviderFactory.diagnoseMissingPackageFragment(ktFile)
}
else {
throw IllegalStateException("Cannot find package fragment for file " + ktFile.name + " with package " + fqName)
}
}
return packageDescriptor!!.getMemberScope()
val packageDescriptor = topLevelDescriptorProvider.getPackageFragmentOrDiagnoseFailure(fqName, ktFile)
return packageDescriptor.getMemberScope()
}
else {
return when (parentDeclaration) {
@@ -137,7 +137,7 @@ public class ResolveSession implements KotlinCodeAnalyzer, LazyClassContext {
@Inject
public void setDelegationFilter(@NotNull DelegationFilter delegationFilter) {
public void setDelegationFilter(@NotNull DelegationFilter delegationFilter) {
this.delegationFilter = delegationFilter;
}
@@ -213,6 +213,18 @@ public class ResolveSession implements KotlinCodeAnalyzer, LazyClassContext {
return packages.invoke(fqName);
}
@NotNull
@Override
public LazyPackageDescriptor getPackageFragmentOrDiagnoseFailure(@NotNull FqName fqName, @Nullable KtFile from) {
LazyPackageDescriptor packageDescriptor = getPackageFragment(fqName);
if (packageDescriptor == null) {
declarationProviderFactory.diagnoseMissingPackageFragment(fqName, from);
assert false : "diagnoseMissingPackageFragment should throw!";
}
return packageDescriptor;
}
@Nullable
private LazyPackageDescriptor createPackage(FqName fqName) {
PackageMemberDeclarationProvider provider = declarationProviderFactory.getPackageMemberDeclarationProvider(fqName);
@@ -350,8 +362,7 @@ public class ResolveSession implements KotlinCodeAnalyzer, LazyClassContext {
) {
result.add(current);
for (FqName subPackage : packageFragmentProvider.getSubPackagesOf(current.getFqName(), MemberScope.Companion.getALL_NAME_FILTER())) {
LazyPackageDescriptor fragment = getPackageFragment(subPackage);
assert fragment != null : "Couldn't find fragment for " + subPackage;
LazyPackageDescriptor fragment = getPackageFragmentOrDiagnoseFailure(subPackage, null);
collectAllPackages(result, fragment);
}
return result;
@@ -19,11 +19,14 @@ package org.jetbrains.kotlin.resolve.lazy
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyPackageDescriptor
interface TopLevelDescriptorProvider {
fun getPackageFragment(fqName: FqName): LazyPackageDescriptor?
fun getPackageFragmentOrDiagnoseFailure(fqName: FqName, from: KtFile?): LazyPackageDescriptor
fun getTopLevelClassifierDescriptors(fqName: FqName, location: LookupLocation): Collection<ClassifierDescriptor>
fun assertValid()
@@ -36,6 +39,10 @@ object NoTopLevelDescriptorProvider : TopLevelDescriptorProvider {
shouldNotBeCalled()
}
override fun getPackageFragmentOrDiagnoseFailure(fqName: FqName, from: KtFile?): LazyPackageDescriptor {
shouldNotBeCalled()
}
override fun getTopLevelClassifierDescriptors(fqName: FqName, location: LookupLocation): Collection<ClassifierDescriptor> {
shouldNotBeCalled()
}
@@ -40,7 +40,11 @@ public abstract class AbstractDeclarationProviderFactory implements DeclarationP
}
@Override
public void diagnoseMissingPackageFragment(KtFile file) {
throw new IllegalStateException("Cannot find package fragment for file " + file.getName() + " with package " + file.getPackageFqName());
public void diagnoseMissingPackageFragment(@NotNull FqName fqName, @Nullable KtFile file) {
String message = "Cannot find package fragment " + fqName;
if (file != null) {
message += "\nvFile = " + file.getVirtualFilePath() + ", file package = '" + file.getPackageFqName() + "'";
}
throw new IllegalStateException(message);
}
}
@@ -34,5 +34,5 @@ public interface DeclarationProviderFactory {
@Nullable
PackageMemberDeclarationProvider getPackageMemberDeclarationProvider(@NotNull FqName packageFqName);
void diagnoseMissingPackageFragment(KtFile file);
void diagnoseMissingPackageFragment(@NotNull FqName fqName, @Nullable KtFile file);
}
@@ -155,7 +155,7 @@ class LocalClassDescriptorHolder(
throw UnsupportedOperationException("Should not be called for top-level declarations")
}
override fun diagnoseMissingPackageFragment(file: KtFile?) {
override fun diagnoseMissingPackageFragment(fqName: FqName, file: KtFile?) {
throw UnsupportedOperationException()
}
}
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.stubindex.resolve
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiManager
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.stubs.StubIndex
import org.jetbrains.kotlin.analyzer.ModuleInfo
@@ -69,21 +70,75 @@ class PluginDeclarationProviderFactory(
return StubBasedPackageMemberDeclarationProvider(name, project, indexedFilesScope)
}
override fun diagnoseMissingPackageFragment(file: KtFile) {
val packageFqName = file.packageFqName
private fun diagnoseMissingPackageFragmentExactPackageIndexCorruption(message: String): Nothing {
throw IllegalStateException(
"KotlinExactPackageIndex seems corrupted.\n" +
message
)
}
private fun diagnoseMissingPackageFragmentPerModulePackageCacheMiss(message: String): Nothing {
throw IllegalStateException(
"PerModulePackageCache miss.\n" +
message
)
}
private fun diagnoseMissingPackageFragmentUnknownReason(message: String): Nothing {
throw IllegalStateException(message)
}
override fun diagnoseMissingPackageFragment(fqName: FqName, file: KtFile?) {
val subpackagesIndex = SubpackagesIndexService.getInstance(project)
val moduleSourceInfo = moduleInfo as? ModuleSourceInfo
val virtualFile = file.virtualFile
throw IllegalStateException("""
Cannot find package fragment for file ${file.name} with package '$packageFqName':
vFile: $virtualFile,
nonIndexed files: $nonIndexedFiles, isNonIndexed: ${file in nonIndexedFiles},
scope = $indexedFilesScope, isInScope = ${virtualFile in indexedFilesScope},
packageExists = ${PackageIndexUtil.packageExists(packageFqName, indexedFilesScope, project)}, cachedPackageExists = ${moduleSourceInfo?.let { project.service<PerModulePackageCacheService>().packageExists(packageFqName, it) }},
oldPackageExists = ${oldPackageExists(packageFqName) ?: "threw exception"},
SPI.packageExists = ${subpackagesIndex.packageExists(packageFqName)}, SPI = $subpackagesIndex, OOCB count ${file.manager.modificationTracker.outOfCodeBlockModificationCount},
ModuleModificationCount = ${moduleSourceInfo?.createModificationTracker()?.modificationCount},
packageFqNameByTree = '${file.packageFqNameByTree}', packageDirectiveText = '${file.packageDirective?.text}'""")
val packageExists = PackageIndexUtil.packageExists(fqName, indexedFilesScope, project)
val spiPackageExists = subpackagesIndex.packageExists(fqName)
val oldPackageExists = oldPackageExists(fqName)
val cachedPackageExists = moduleSourceInfo?.let { project.service<PerModulePackageCacheService>().packageExists(fqName, it) }
val moduleModificationCount = moduleSourceInfo?.createModificationTracker()?.modificationCount
val common = """
packageExists = $packageExists, cachedPackageExists = $cachedPackageExists,
oldPackageExists = $oldPackageExists,
SPI.packageExists = $spiPackageExists, SPI = $subpackagesIndex,
OOCB count = ${PsiManager.getInstance(project).modificationTracker.outOfCodeBlockModificationCount}
moduleModificationCount = $moduleModificationCount
""".trimIndent()
val message = if (file != null) {
val virtualFile = file.virtualFile
val inScope = virtualFile in indexedFilesScope
val packageFqName = file.packageFqName
"""
|Cannot find package fragment '$fqName' for file ${file.name}, file package = '$packageFqName':
|vFile: $virtualFile,
|nonIndexedFiles = $nonIndexedFiles, isNonIndexed = ${file in nonIndexedFiles},
|scope = $indexedFilesScope, isInScope = $inScope,
|$common,
|packageFqNameByTree = '${file.packageFqNameByTree}', packageDirectiveText = '${file.packageDirective?.text}'
""".trimMargin()
}
else {
"""
|Cannot find package fragment '$fqName' for unspecified file:
|nonIndexedFiles = $nonIndexedFiles,
|scope = $indexedFilesScope,
|$common
""".trimMargin()
}
val scopeNotEmptyAndContainsFile =
indexedFilesScope != GlobalSearchScope.EMPTY_SCOPE && (file == null || file.virtualFile in indexedFilesScope)
when {
scopeNotEmptyAndContainsFile
&& !packageExists && oldPackageExists == false -> diagnoseMissingPackageFragmentExactPackageIndexCorruption(message)
scopeNotEmptyAndContainsFile
&& packageExists && cachedPackageExists == false -> diagnoseMissingPackageFragmentPerModulePackageCacheMiss(message)
else -> diagnoseMissingPackageFragmentUnknownReason(message)
}
}
// trying to diagnose org.jetbrains.kotlin.resolve.lazy.NoDescriptorForDeclarationException in completion