Commit 469e765d authored by Elena Shaverdova's avatar Elena Shaverdova Committed by intellij-monorepo-bot
Browse files

Rework reporting other *Stub* exceptions IDEA-331326 Create FUS event for stub index inconsistency

(cherry picked from commit a59d3c32d5c013c091fbfcf8db6b21927707ca4d)

IJ-CR-132215

GitOrigin-RevId: 4f506f230f583f5e0c15eb6a987c27e8882f4647
parent 5702a1e8
Branches unavailable Tags unavailable
No related merge requests found
Showing with 82 additions and 135 deletions
+82 -135
......@@ -15,45 +15,27 @@ public interface StubInconsistencyReporter {
}
enum SourceOfCheck {
DeliberateAdditionalCheckInCompletion(
"deliberate_additional_check_in_completion"), //Registry.is("ide.check.stub.text.consistency") is enabled
DeliberateAdditionalCheckInIntentions(
"deliberate_additional_check_in_intentions"), //Registry.is("ide.check.stub.text.consistency") is enabled
WrongTypePsiInStubHelper("wrong_type_psi_in_stub_helper"),
OffsetOutsideFileInJava("offset_outside_file_in_java"),
CheckAfterExceptionInJava("check_after_exception_in_java"),
NoPsiMatchingASTinJava("no_psi_matching_ast_in_java"),
ForTests("for_tests"),//is definitely not expected to actually appear in FUS
Other("other");
private final String fusDescription;
SourceOfCheck(String fusDescription) {
this.fusDescription = fusDescription;
}
public String getFusDescription() {
return fusDescription;
}
DeliberateAdditionalCheckInCompletion, //Registry.is("ide.check.stub.text.consistency") is enabled
DeliberateAdditionalCheckInIntentions, //Registry.is("ide.check.stub.text.consistency") is enabled
WrongTypePsiInStubHelper,
OffsetOutsideFileInJava,
CheckAfterExceptionInJava,
NoPsiMatchingASTinJava,
ForTests,//is definitely not expected to actually appear in FUS
Other //better use null
}
enum InconsistencyType {
DifferentNumberOfPsiTrees("different_number_of_psi_trees"), MismatchingPsiTree("mismatching_psi_tree");
private final String fusDescription;
InconsistencyType(String fusDescription) {
this.fusDescription = fusDescription;
}
public String getFusDescription() {
return fusDescription;
}
DifferentNumberOfPsiTrees, MismatchingPsiTree
}
/**
* Sometimes stub inconsistency related exception is thrown even when no inconsistency is found during the usual check
* Sometimes stub inconsistency-related exception is thrown even when no inconsistency is found during the usual check
*
* @deprecated all related methods are deprecated
*/
@Deprecated
enum EnforcedInconsistencyType {
PsiOfUnexpectedClass("psi_of_unexpected_class"), Other("other");
private final String fusDescription;
......@@ -62,14 +44,27 @@ public interface StubInconsistencyReporter {
this.fusDescription = fusDescription;
}
@SuppressWarnings("unused")
public String getFusDescription() {
return fusDescription;
}
}
void reportStubInconsistency(@NotNull Project project,
@Nullable StubInconsistencyReporter.SourceOfCheck reason,
@Nullable InconsistencyType type);
/**
* @deprecated Use {@link #reportStubInconsistency(Project, SourceOfCheck, InconsistencyType)}
*/
@Deprecated
void reportEnforcedStubInconsistency(@NotNull Project project, @NotNull StubInconsistencyReporter.SourceOfCheck reason,
@NotNull EnforcedInconsistencyType enforcedInconsistencyType);
/**
* @deprecated Use {@link #reportStubInconsistency(Project, SourceOfCheck, InconsistencyType)}
*/
@Deprecated
void reportStubInconsistency(@NotNull Project project, @NotNull StubInconsistencyReporter.SourceOfCheck reason,
@NotNull InconsistencyType type,
@Nullable EnforcedInconsistencyType enforcedInconsistencyType);
......
......@@ -59,38 +59,43 @@ public final class StubTextInconsistencyException extends RuntimeException imple
*/
@SuppressWarnings("unused")
public static void checkStubTextConsistency(@NotNull PsiFile file) {
checkStubTextConsistency(file, SourceOfCheck.Other, null);
checkStubTextConsistency(file, null);
}
public static void checkStubTextConsistency(@NotNull PsiFile file, @NotNull StubInconsistencyReporter.SourceOfCheck reason) {
checkStubTextConsistency(file, reason, null);
/**
* Left for backward compatibility.
*
* @deprecated Use {@link #checkStubTextConsistency(PsiFile, SourceOfCheck)}
*/
@Deprecated
public static void checkStubTextConsistency(@NotNull PsiFile file,
@NotNull StubInconsistencyReporter.SourceOfCheck reason,
@SuppressWarnings("unused")
@Nullable StubInconsistencyReporter.EnforcedInconsistencyType enforcedInconsistencyType) {
checkStubTextConsistency(file, reason);
}
/**
* Parameters reason and enforcedInconsistencyType are used for tracking statistic of the errors' sources.
* {@link StubInconsistencyReporter.SourceOfCheck#Other} and {@code null} are recommended values for callers outside IntelliJ repository.
* `reason` parameter is used for tracking statistic of the errors' sources.
* {@code null} is recommended values for callers outside IntelliJ repository.
*/
public static void checkStubTextConsistency(@NotNull PsiFile file,
@NotNull StubInconsistencyReporter.SourceOfCheck reason,
@Nullable StubInconsistencyReporter.EnforcedInconsistencyType enforcedInconsistencyType)
@Nullable StubInconsistencyReporter.SourceOfCheck reason)
throws StubTextInconsistencyException {
PsiUtilCore.ensureValid(file);
FileViewProvider viewProvider = file.getViewProvider();
if (viewProvider instanceof FreeThreadedFileViewProvider || viewProvider.getVirtualFile() instanceof LightVirtualFile) {
reportInconsistency(file, reason, null, enforcedInconsistencyType);
return;
}
PsiFile bindingRoot = viewProvider.getStubBindingRoot();
if (!(bindingRoot instanceof PsiFileImpl)) {
reportInconsistency(file, reason, null, enforcedInconsistencyType);
return;
}
IStubFileElementType<?> fileElementType = ((PsiFileImpl)bindingRoot).getElementTypeForStubBuilder();
if (fileElementType == null || !fileElementType.shouldBuildStubFor(viewProvider.getVirtualFile())) {
reportInconsistency(file, reason, null, enforcedInconsistencyType);
return;
}
......@@ -100,7 +105,7 @@ public final class StubTextInconsistencyException extends RuntimeException imple
.map(StubTreeBuilder.getStubbedRoots(viewProvider), p -> (PsiFileStub<?>)((PsiFileImpl)p.getSecond()).calcStubTree().getRoot());
if (fromPsi.size() != fromText.size()) {
reportInconsistency(file, reason, InconsistencyType.DifferentNumberOfPsiTrees, enforcedInconsistencyType);
reportInconsistency(file, reason, InconsistencyType.DifferentNumberOfPsiTrees);
throw new StubTextInconsistencyException("Inconsistent stub roots: " +
"PSI says it's " + ContainerUtil.map(fromPsi, s -> s.getType()) +
" but re-parsing the text gives " + ContainerUtil.map(fromText, s -> s.getType()),
......@@ -110,24 +115,17 @@ public final class StubTextInconsistencyException extends RuntimeException imple
for (int i = 0; i < fromPsi.size(); i++) {
PsiFileStub<?> psiStub = fromPsi.get(i);
if (!DebugUtil.stubTreeToString(psiStub).equals(DebugUtil.stubTreeToString(fromText.get(i)))) {
reportInconsistency(file, reason, InconsistencyType.MismatchingPsiTree, enforcedInconsistencyType);
reportInconsistency(file, reason, InconsistencyType.MismatchingPsiTree);
throw new StubTextInconsistencyException("Stub is inconsistent with text in " + file.getLanguage(),
file, fromText, fromPsi);
}
}
reportInconsistency(file, reason, null, enforcedInconsistencyType);
}
private static void reportInconsistency(@NotNull PsiFile file, @NotNull StubInconsistencyReporter.SourceOfCheck reason,
@Nullable InconsistencyType inconsistencyType,
@Nullable StubInconsistencyReporter.EnforcedInconsistencyType enforcedInconsistencyType) {
if (inconsistencyType == null) {
if (enforcedInconsistencyType != null) {
StubInconsistencyReporter.getInstance().reportEnforcedStubInconsistency(file.getProject(), reason, enforcedInconsistencyType);
}
return;
}
StubInconsistencyReporter.getInstance().reportStubInconsistency(file.getProject(), reason, inconsistencyType, enforcedInconsistencyType);
private static void reportInconsistency(@NotNull PsiFile file,
@Nullable StubInconsistencyReporter.SourceOfCheck reason,
@NotNull InconsistencyType inconsistencyType) {
StubInconsistencyReporter.getInstance().reportStubInconsistency(file.getProject(), reason, inconsistencyType);
}
private static @NotNull List<PsiFileStub<?>> restoreStubsFromText(FileViewProvider viewProvider) {
......
......@@ -17,6 +17,7 @@ import com.intellij.psi.impl.DebugUtil;
import com.intellij.psi.impl.source.PsiFileWithStubSupport;
import com.intellij.psi.tree.IStubFileElementType;
import com.intellij.util.Function;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
......@@ -54,14 +55,15 @@ public abstract class StubTreeLoader {
}
/**
* Creates exception with full description. Should be used when requesting indexes is safe,
* in particular counting indexes for changed files won't need some already taken lock.
* Creates exception with full description.
* Should be used when requesting indexes is safe, in particular, counting indexes for changed files won't need some already taken lock.
* <p/>
* From under lock, which may be needed to compute indexes for changed files,
* use {@link StubTreeLoader#createCoarseExceptionStubTreeAndIndexDoNotMatch(ObjectStubTree, PsiFileWithStubSupport, Throwable,
* StubInconsistencyReporter.StubTreeAndIndexDoNotMatchSource)}
* and invoke {@link StubTreeAndIndexUnmatchCoarseException#createCompleteException()} outside the lock.
*/
@ApiStatus.Internal
public @NotNull RuntimeException stubTreeAndIndexDoNotMatch(
@Nullable ObjectStubTree<?> stubTree,
@NotNull PsiFileWithStubSupport psiFile,
......@@ -73,22 +75,11 @@ public abstract class StubTreeLoader {
});
}
/**
* @deprecated Use @{link {@link #stubTreeAndIndexDoNotMatch(ObjectStubTree, PsiFileWithStubSupport, Throwable,
* StubInconsistencyReporter.StubTreeAndIndexDoNotMatchSource)}}
*/
@Deprecated
public @NotNull RuntimeException stubTreeAndIndexDoNotMatch(@Nullable ObjectStubTree<?> stubTree,
@NotNull PsiFileWithStubSupport psiFile,
@Nullable Throwable cause) {
return stubTreeAndIndexDoNotMatch(stubTree, psiFile, cause, null);
}
/**
* @see StubTreeLoader#stubTreeAndIndexDoNotMatch(ObjectStubTree, PsiFileWithStubSupport, Throwable,
* StubInconsistencyReporter.StubTreeAndIndexDoNotMatchSource)
*/
@ApiStatus.Internal
public @NotNull StubTreeAndIndexUnmatchCoarseException createCoarseExceptionStubTreeAndIndexDoNotMatch(
@Nullable ObjectStubTree<?> stubTree,
@NotNull PsiFileWithStubSupport psiFile,
......@@ -100,19 +91,6 @@ public abstract class StubTreeLoader {
});
}
/**
* @deprecated Use {@link #createCoarseExceptionStubTreeAndIndexDoNotMatch(ObjectStubTree, PsiFileWithStubSupport, Throwable,
* StubInconsistencyReporter.StubTreeAndIndexDoNotMatchSource)}
*/
@Deprecated
public @NotNull StubTreeAndIndexUnmatchCoarseException createCoarseExceptionStubTreeAndIndexDoNotMatch(
@Nullable ObjectStubTree<?> stubTree,
@NotNull PsiFileWithStubSupport psiFile,
@Nullable Throwable cause
) {
return createCoarseExceptionStubTreeAndIndexDoNotMatch(stubTree, psiFile, cause, null);
}
private @NotNull StubTreeAndIndexUnmatchCoarseException doCreateCoarseExceptionStubTreeAndIndexDoNotMatch(
@Nullable ObjectStubTree<?> stubTree,
@NotNull PsiFileWithStubSupport psiFile,
......
......@@ -15,7 +15,6 @@ import com.intellij.psi.impl.source.PsiFileWithStubSupport;
import com.intellij.psi.impl.source.StubbedSpine;
import com.intellij.psi.search.FileTypeIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.StubInconsistencyReporter.EnforcedInconsistencyType;
import com.intellij.psi.stubs.StubInconsistencyReporter.SourceOfCheck;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
......@@ -130,7 +129,7 @@ public abstract class StubProcessingHelperBase {
if (psiFile instanceof PsiBinaryFile) {
// a file can be indexed as containing stubs,
// but then in a specific project FileViewProviderFactory can decide not to create stub-aware PSI
// because the file isn't in expected location
// because the file isn't in the expected location
return true;
}
......@@ -165,9 +164,7 @@ public abstract class StubProcessingHelperBase {
@Nullable StubInconsistencyReporter.StubTreeAndIndexDoNotMatchSource source
) {
try {
StubTextInconsistencyException.checkStubTextConsistency(psiFile,
SourceOfCheck.WrongTypePsiInStubHelper,
EnforcedInconsistencyType.PsiOfUnexpectedClass);
StubTextInconsistencyException.checkStubTextConsistency(psiFile, SourceOfCheck.WrongTypePsiInStubHelper);
LOG.error(extraMessage + "\n" + StubTreeLoader.getInstance().stubTreeAndIndexDoNotMatch(stubTree, psiFile, null, source));
}
finally {
......
......@@ -8,9 +8,6 @@ import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesColle
import com.intellij.internal.statistic.utils.StatisticsUtil
import com.intellij.openapi.extensions.PluginId
import com.intellij.openapi.project.Project
import com.intellij.psi.stubs.StubInconsistencyReporter
import com.intellij.psi.stubs.StubInconsistencyReporter.InconsistencyType
import com.intellij.psi.stubs.StubInconsistencyReporter.SourceOfCheck
import com.intellij.util.indexing.FileBasedIndex.RebuildRequestedByUserAction
import com.intellij.util.indexing.ID
import org.jetbrains.annotations.ApiStatus.Internal
......@@ -18,46 +15,7 @@ import java.util.*
@Internal
object IndexStatisticGroup {
val GROUP = EventLogGroup("indexing.statistics", 12)
private val sourceOfCheckField =
EventFields.Enum<SourceOfCheck>("check_source") { type -> type.fusDescription }
private val inconsistencyTypeField = EventFields.Enum<InconsistencyType>("inconsistency_type") { type -> type.fusDescription }
private val enforcedInconsistencyTypeField =
EventFields.Enum<StubInconsistencyReporter.EnforcedInconsistencyType>("enforced_inconsistency") { type -> type.fusDescription }
private val stubIndexInconsistencyRegistered = GROUP.registerVarargEvent("stub.index.inconsistency", sourceOfCheckField,
inconsistencyTypeField, enforcedInconsistencyTypeField)
@JvmStatic
fun reportEnforcedStubInconsistency(project: Project,
sourceOfCheck: SourceOfCheck,
enforcedInconsistencyType: StubInconsistencyReporter.EnforcedInconsistencyType) {
stubIndexInconsistencyRegistered.log(project,
sourceOfCheckField.with(sourceOfCheck),
enforcedInconsistencyTypeField.with(enforcedInconsistencyType))
}
/**
* `stub.index.inconsistency` event with only a project in versions of collector <= 11
* corresponds in collectors of version 12+ to a `stub.index.inconsistency` event with a project,
* SourceOfCheck.WrongTypePsiInStubHelper,
* any InconsistencyType including none,
* and EnforcedInconsistencyType.PsiOfUnexpectedClass
*/
@JvmStatic
fun reportStubInconsistency(project: Project,
sourceOfCheck: SourceOfCheck,
inconsistencyType: InconsistencyType,
enforcedInconsistencyType: StubInconsistencyReporter.EnforcedInconsistencyType?) {
if (enforcedInconsistencyType == null) {
stubIndexInconsistencyRegistered.log(project, sourceOfCheckField.with(sourceOfCheck), inconsistencyTypeField.with(inconsistencyType))
}
else {
stubIndexInconsistencyRegistered.log(project, sourceOfCheckField.with(sourceOfCheck), inconsistencyTypeField.with(inconsistencyType),
enforcedInconsistencyTypeField.with(enforcedInconsistencyType))
}
}
val GROUP = EventLogGroup("indexing.statistics", 13)
private val indexIdField =
EventFields.StringValidatedByCustomRule("index_id", IndexIdRuleValidator::class.java)
......
......@@ -7,7 +7,7 @@ import com.intellij.internal.statistic.eventLog.events.EventId2
import com.intellij.internal.statistic.eventLog.events.EventPair
import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector
import com.intellij.openapi.project.Project
import com.intellij.psi.stubs.StubInconsistencyReporter.StubTreeAndIndexDoNotMatchSource
import com.intellij.psi.stubs.StubInconsistencyReporter.*
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
......@@ -53,6 +53,20 @@ object StubInconsistencyReportUtil {
STUB_TREE_AND_INDEX_DO_NOT_MATCH_EVENT.log(project, EventPair(STUB_TREE_AND_INDEX_DO_NOT_MATCH_SOURCE_FIELD, source))
}
}
private val CHECK_REASON_FIELD = EventFields.Enum<SourceOfCheck>("reason")
private val INCONSISTENCY_TYPE_FIELD = EventFields.Enum<InconsistencyType>("type")
private val STUB_INCONSISTENCY_EVENT = GROUP.registerVarargEvent(
"stub.inconsistency", CHECK_REASON_FIELD, INCONSISTENCY_TYPE_FIELD
)
@JvmStatic
fun reportStubInconsistency(project: Project, reason: SourceOfCheck?, type: InconsistencyType?) {
val parameters = mutableListOf<EventPair<*>>()
reason?.let { parameters.add(CHECK_REASON_FIELD.with(it)) }
type?.let { parameters.add(INCONSISTENCY_TYPE_FIELD.with(it)) }
STUB_INCONSISTENCY_EVENT.log(project, parameters)
}
}
......
......@@ -9,19 +9,26 @@ import org.jetbrains.annotations.Nullable;
@ApiStatus.Internal
public class StubInconsistencyReporterImpl implements StubInconsistencyReporter {
@Override
public void reportStubInconsistency(@NotNull Project project,
@Nullable SourceOfCheck reason,
@Nullable InconsistencyType type) {
StubInconsistencyReportUtil.reportStubInconsistency(project, reason, type);
}
@Override
public void reportEnforcedStubInconsistency(@NotNull Project project,
@NotNull StubInconsistencyReporter.SourceOfCheck reason,
@NotNull EnforcedInconsistencyType enforcedInconsistencyType) {
IndexStatisticGroup.reportEnforcedStubInconsistency(project, reason, enforcedInconsistencyType);
@SuppressWarnings("deprecation") @NotNull EnforcedInconsistencyType enforcedInconsistencyType) {
StubInconsistencyReportUtil.reportStubInconsistency(project, reason, null);
}
@Override
public void reportStubInconsistency(@NotNull Project project,
@NotNull StubInconsistencyReporter.SourceOfCheck reason,
@NotNull InconsistencyType type,
@Nullable EnforcedInconsistencyType enforcedInconsistencyType) {
IndexStatisticGroup.reportStubInconsistency(project, reason, type, enforcedInconsistencyType);
@SuppressWarnings("deprecation") @Nullable EnforcedInconsistencyType enforcedInconsistencyType) {
StubInconsistencyReportUtil.reportStubInconsistency(project, reason, type);
}
@Override
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment