Skip to content

Commit 3c8428f

Browse files
authored
fix psi exceptions (#185)
1 parent 65df0d6 commit 3c8428f

File tree

18 files changed

+544
-205
lines changed

18 files changed

+544
-205
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package org.digma.intellij.plugin.common;
2+
3+
import com.intellij.openapi.diagnostic.Logger;
4+
import org.digma.intellij.plugin.log.Log;
5+
6+
public class Retries {
7+
8+
private Retries() {
9+
}
10+
11+
private static final Logger LOGGER = Logger.getInstance(Retries.class);
12+
13+
public static void simpleRetry(Runnable runnable,Class<? extends Throwable> retryOn,int backOffMillis,int maxRetries){
14+
simpleRetry(runnable,retryOn,backOffMillis,maxRetries,1);
15+
}
16+
17+
private static void simpleRetry(Runnable runnable,Class<? extends Throwable> retryOn,int backOffMillis,int maxRetries,int retryCount){
18+
19+
try{
20+
runnable.run();
21+
}catch (Throwable e){
22+
23+
Log.log(LOGGER::warn,"get exception "+e+ " retry "+retryCount);
24+
Log.warnWithException(LOGGER,e,"exception in simpleRetry");
25+
26+
if (retryCount == maxRetries){
27+
throw e;
28+
}
29+
30+
31+
32+
if (retryOn.isAssignableFrom(e.getClass())){
33+
try {
34+
Log.log(LOGGER::warn,"sleeping");
35+
Thread.sleep(backOffMillis);
36+
} catch (InterruptedException ex) {/* ignore*/}
37+
simpleRetry(runnable,retryOn,backOffMillis,maxRetries,retryCount+1);
38+
}else{
39+
throw e;
40+
}
41+
}
42+
}
43+
44+
45+
}

ide-common/src/main/java/org/digma/intellij/plugin/editor/CaretListener.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.intellij.openapi.project.Project;
99
import com.intellij.openapi.util.Disposer;
1010
import com.intellij.openapi.vfs.VirtualFile;
11+
import com.intellij.psi.PsiDocumentManager;
1112
import com.intellij.psi.PsiFile;
1213
import com.intellij.psi.PsiManager;
1314
import com.intellij.util.Alarm;
@@ -60,8 +61,21 @@ class CaretListener {
6061

6162

6263
//don't install listeners on non-supported files, this method shouldn't be called for non-supported files.
63-
void maybeAddCaretListener(@NotNull Editor editor, @NotNull VirtualFile file) {
64+
void maybeAddCaretListener(@NotNull Editor editor) {
6465

66+
if (editor.isDisposed()) {
67+
Log.log(LOGGER::debug, "not installing listener for {} because it is disposed", editor);
68+
return;
69+
}
70+
71+
var psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
72+
if (psiFile == null){
73+
return;
74+
}
75+
76+
var file = psiFile.getVirtualFile();
77+
78+
//this is a check if this editor already has a caret listener
6579
if (disposables.containsKey(file)) {
6680
return;
6781
}
@@ -86,10 +100,6 @@ private void addCaretListener(@NotNull Editor editor, @NotNull VirtualFile file)
86100
clicks the editor quickly or moves around with the keyboard.
87101
*/
88102

89-
if (editor.isDisposed()) {
90-
Log.log(LOGGER::debug, "not installing listener for {} because it is disposed", editor);
91-
return;
92-
}
93103

94104
Disposable parentDisposable = Disposer.newDisposable();
95105
disposables.put(file, parentDisposable);

ide-common/src/main/java/org/digma/intellij/plugin/editor/DocumentChangeListener.java

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import com.intellij.openapi.vfs.VirtualFile;
1313
import com.intellij.psi.PsiDocumentManager;
1414
import com.intellij.psi.PsiFile;
15+
import com.intellij.psi.PsiInvalidElementAccessException;
1516
import com.intellij.util.Alarm;
1617
import com.intellij.util.AlarmFactory;
1718
import com.intellij.util.indexing.FileBasedIndex;
@@ -22,6 +23,7 @@
2223
import org.digma.intellij.plugin.model.discovery.DocumentInfo;
2324
import org.digma.intellij.plugin.model.discovery.MethodUnderCaret;
2425
import org.digma.intellij.plugin.psi.LanguageService;
26+
import org.digma.intellij.plugin.psi.LanguageServiceLocator;
2527
import org.digma.intellij.plugin.ui.CaretContextService;
2628
import org.jetbrains.annotations.NotNull;
2729

@@ -41,60 +43,91 @@ class DocumentChangeListener {
4143
private final DocumentInfoService documentInfoService;
4244
private final CaretContextService caretContextService;
4345

44-
private final Alarm documentChangeAlarm;
45-
4646
private final Map<VirtualFile, Disposable> disposables = new HashMap<>();
4747

4848
DocumentChangeListener(Project project) {
4949
this.project = project;
5050
documentInfoService = project.getService(DocumentInfoService.class);
5151
caretContextService = project.getService(CaretContextService.class);
52-
documentChangeAlarm = AlarmFactory.getInstance().create();
5352
}
5453

55-
void maybeAddDocumentListener(Editor editor, PsiFile psiFile, LanguageService languageService) {
56-
if (disposables.containsKey(psiFile.getVirtualFile())) {
54+
void maybeAddDocumentListener(@NotNull Editor editor) {
55+
56+
if (editor.isDisposed()) {
57+
Log.log(LOGGER::debug, "not installing document listener for {} because it is disposed", editor);
5758
return;
5859
}
5960

60-
addDocumentListener(editor, psiFile, languageService);
61-
}
61+
Document document = editor.getDocument();
62+
PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document);
63+
//probably should never happen
64+
if (psiFile == null) {
65+
return;
66+
}
6267

63-
private void addDocumentListener(@NotNull Editor editor, @NotNull PsiFile psiFile, @NotNull LanguageService languageService) {
68+
VirtualFile virtualFile = psiFile.getVirtualFile();
6469

65-
if (editor.isDisposed()) {
66-
Log.log(LOGGER::debug, "not installing document listener for {} because it is disposed", editor);
70+
//this is a check if this document already has a document listener
71+
if (disposables.containsKey(virtualFile)) {
6772
return;
6873
}
6974

75+
addDocumentListener(editor, virtualFile);
76+
}
77+
78+
private void addDocumentListener(@NotNull Editor editor, @NotNull VirtualFile virtualFile) {
79+
7080
Document document = editor.getDocument();
7181

7282
Disposable parentDisposable = Disposer.newDisposable();
73-
disposables.put(psiFile.getVirtualFile(), parentDisposable);
74-
Log.log(LOGGER::debug, "adding document listener for file:{}", psiFile.getVirtualFile());
83+
disposables.put(virtualFile, parentDisposable);
84+
Log.log(LOGGER::debug, "adding document listener for file:{}", virtualFile);
7585

7686
document.addDocumentListener(new DocumentListener() {
87+
88+
private final Alarm documentChangeAlarm = AlarmFactory.getInstance().create();
89+
7790
@Override
7891
public void documentChanged(@NotNull DocumentEvent event) {
7992

93+
if (project.isDisposed()) {
94+
return;
95+
}
96+
8097
documentChangeAlarm.cancelAllRequests();
8198
documentChangeAlarm.addRequest(() ->
82-
processDocumentChanged(editor, psiFile, languageService), 300);
99+
{
100+
//this code is always executed in smart mode because the listener is installed only in smart mode
101+
PsiFile fileToQuery = PsiDocumentManager.getInstance(project).getPsiFile(event.getDocument());
102+
//probably should never happen
103+
if (fileToQuery == null) {
104+
return;
105+
}
106+
try {
107+
108+
processDocumentChanged(editor, fileToQuery);
109+
} catch (PsiInvalidElementAccessException e) {
110+
Log.debugWithException(LOGGER, e, "exception while processing file: {}, {}", fileToQuery.getVirtualFile(), e.getMessage());
111+
}
112+
113+
}, 500);
83114

84115
}
85116
}, parentDisposable);
86117
}
87118

88119

89-
private void processDocumentChanged(@NotNull Editor editor, @NotNull PsiFile psiFile, @NotNull LanguageService languageService) {
120+
private void processDocumentChanged(@NotNull Editor editor, @NotNull PsiFile psiFile) {
90121

91-
if (project.isDisposed()){
122+
if (project.isDisposed()) {
92123
return;
93124
}
94125

95126

96-
97127
PsiDocumentManager.getInstance(project).performLaterWhenAllCommitted(() -> {
128+
129+
LanguageService languageService = LanguageServiceLocator.getInstance(project).locate(psiFile.getLanguage());
130+
98131
DocumentInfo documentInfo;
99132
try {
100133
Map<Integer, DocumentInfo> documentInfoMap =
@@ -113,6 +146,7 @@ private void processDocumentChanged(@NotNull Editor editor, @NotNull PsiFile psi
113146

114147
} catch (IndexNotReadyException e) {
115148
//IndexNotReadyException will be thrown on dumb mode, when indexing is still in progress.
149+
//usually it should not happen because the listener is installed only in smart mode.
116150
documentInfo = languageService.buildDocumentInfo(psiFile);
117151
}
118152

@@ -124,7 +158,7 @@ private void processDocumentChanged(@NotNull Editor editor, @NotNull PsiFile psi
124158

125159
MethodUnderCaret methodUnderCaret = languageService.detectMethodUnderCaret(project, psiFile, editor.getCaretModel().getOffset());
126160

127-
update(languageService,psiFile, documentInfo, methodUnderCaret);
161+
update(languageService, psiFile, documentInfo, methodUnderCaret);
128162

129163
});
130164
}
@@ -137,7 +171,7 @@ private void update(@NotNull LanguageService languageService, @NotNull PsiFile p
137171
//contextChanged will update the UI and must run after documentInfoService.addCodeObjects is finished
138172
//enrichDocumentInfo is meant mainly to discover spans. the DocumentInfoIndex can
139173
// not discover spans because there is no reference resolving during file based index.
140-
languageService.enrichDocumentInfo(documentInfo,psiFile);
174+
languageService.enrichDocumentInfo(documentInfo, psiFile);
141175
documentInfoService.addCodeObjects(psiFile, documentInfo);
142176
caretContextService.contextChanged(methodUnderCaret);
143177
});

0 commit comments

Comments
 (0)