Skip to content

Commit b994418

Browse files
committed
FIX: Cannot invoke "com.intellij.psi.PsiFile.getProject()" because the return value of "net.seesharpsoft.intellij.plugins.csv.psi.CsvPsiTreeUpdater.getPsiFile()" is null #378
lazy initialization and additional null checks
1 parent cb56ae7 commit b994418

File tree

3 files changed

+47
-33
lines changed

3 files changed

+47
-33
lines changed

src/main/java/net/seesharpsoft/intellij/plugins/csv/psi/CsvPsiTreeUpdater.java

+45-31
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22

33
import com.intellij.openapi.application.ApplicationManager;
44
import com.intellij.openapi.command.CommandProcessor;
5-
import com.intellij.openapi.diagnostic.Logger;
65
import com.intellij.openapi.editor.Document;
76
import com.intellij.openapi.fileTypes.FileType;
87
import com.intellij.openapi.util.Pair;
98
import com.intellij.openapi.util.TextRange;
109
import com.intellij.psi.*;
11-
import com.intellij.psi.impl.source.tree.LeafPsiElement;
1210
import com.intellij.psi.util.PsiTreeUtil;
1311
import com.intellij.util.DocumentUtil;
1412
import net.seesharpsoft.intellij.plugins.csv.CsvHelper;
@@ -26,56 +24,62 @@
2624

2725
public class CsvPsiTreeUpdater implements PsiFileHolder, Suspendable {
2826

29-
private final static Logger LOG = Logger.getInstance(CsvPsiTreeUpdater.class);
27+
protected final EventListenerList myEventListenerList = new EventListenerList();
3028

3129
private final PsiFileHolder myPsiFileHolder;
3230

33-
private final PsiFileFactory myFileFactory;
34-
35-
private final CsvPsiParserFileType myFileType;
31+
private PsiFileFactory myFileFactory;
3632

37-
protected final EventListenerList myEventListenerList = new EventListenerList();
33+
private CsvPsiParserFileType myFileType;
3834

3935
private List<PsiAction> myUncommittedActions = new ArrayList<>();
4036

4137
public CsvPsiTreeUpdater(@NotNull PsiFileHolder psiFileHolder) {
4238
myPsiFileHolder = psiFileHolder;
43-
myFileFactory = PsiFileFactory.getInstance(getPsiFile().getProject());
44-
myFileType = new CsvPsiParserFileType(CsvHelper.getValueSeparator(psiFileHolder.getPsiFile()), CsvHelper.getEscapeCharacter(psiFileHolder.getPsiFile()));
4539
}
4640

4741
private FileType getFileType() {
48-
myFileType.setSeparator(CsvHelper.getValueSeparator(getPsiFile()));
49-
myFileType.setEscapeCharacter(CsvHelper.getEscapeCharacter(getPsiFile()));
42+
PsiFile psiFile = getPsiFile();
43+
if (psiFile == null) return null;
44+
45+
if (myFileType == null) {
46+
myFileType = new CsvPsiParserFileType(CsvHelper.getValueSeparator(psiFile), CsvHelper.getEscapeCharacter(psiFile));
47+
} else {
48+
myFileType.setSeparator(CsvHelper.getValueSeparator(psiFile));
49+
myFileType.setEscapeCharacter(CsvHelper.getEscapeCharacter(psiFile));
50+
}
5051
return myFileType;
5152
}
5253

54+
private PsiFileFactory getFileFactory() {
55+
PsiFile psiFile = getPsiFile();
56+
if (psiFile == null) return null;
57+
58+
if (myFileFactory == null) {
59+
myFileFactory = PsiFileFactory.getInstance(getPsiFile().getProject());
60+
}
61+
return myFileFactory;
62+
}
63+
5364
private PsiFile createFile(@NotNull String text) {
54-
return myFileFactory.createFileFromText("a.csv", getFileType(), text);
65+
PsiFileFactory fileFactory = getFileFactory();
66+
return fileFactory == null ? null : getFileFactory().createFileFromText("a.csv", getFileType(), text);
5567
}
5668

5769
private boolean isIndicatingComment(@NotNull String text) {
5870
return text.trim().startsWith(CsvEditorSettings.getInstance().getCommentIndicator());
5971
}
6072

61-
public @NotNull CsvField createField(@NotNull String text, boolean enquoteCommentIndicator) {
73+
public @Nullable CsvField createField(@NotNull String text, boolean enquoteCommentIndicator) {
6274
boolean enforceQuoting = CsvEditorSettings.getInstance().isQuotingEnforced();
6375
if (enquoteCommentIndicator && isIndicatingComment(text)) enforceQuoting = true;
6476

6577
String sanitizedValue = CsvHelper.quoteCsvField(text, CsvHelper.getEscapeCharacter(getPsiFile()), CsvHelper.getValueSeparator(getPsiFile()), enforceQuoting);
6678

67-
CsvField field = SyntaxTraverser.psiTraverser(createFile(sanitizedValue)).filter(CsvField.class).first();
68-
if (field == null) {
69-
LOG.warn(
70-
CsvHelper.formatString("Couldn't create field for text: ${sanitizedValue}",
71-
Collections.singletonMap("sanitizedValue", sanitizedValue))
72-
);
73-
field = (CsvField) CsvTypes.Factory.createElement(new LeafPsiElement(CsvTypes.FIELD, ""));
74-
}
75-
return field;
79+
return SyntaxTraverser.psiTraverser(createFile(sanitizedValue)).filter(CsvField.class).first();
7680
}
7781

78-
public @NotNull CsvRecord createRecord() {
82+
public @Nullable CsvRecord createRecord() {
7983
return SyntaxTraverser.psiTraverser(createFile("\n")).filter(CsvRecord.class).first();
8084
}
8185

@@ -85,6 +89,8 @@ private boolean isIndicatingComment(@NotNull String text) {
8589

8690
public Document getDocument() {
8791
PsiFile psiFile = getPsiFile();
92+
if (psiFile == null) return null;
93+
8894
return PsiDocumentManager.getInstance(psiFile.getProject()).getDocument(psiFile);
8995
}
9096

@@ -332,6 +338,7 @@ public synchronized void commit() {
332338

333339
suspend();
334340
List<PsiAction> actionsToCommit = new ArrayList<>(myUncommittedActions);
341+
myUncommittedActions.clear();
335342
if (!doCommit(() -> {
336343
try {
337344
actionsToCommit.forEach(PsiAction::execute);
@@ -341,16 +348,15 @@ public synchronized void commit() {
341348
}
342349
})) {
343350
resume();
344-
} else {
345-
myUncommittedActions.clear();
346351
}
347352
}
348353

349354
private boolean doCommit(@NotNull Runnable runnable) {
350-
if (!getPsiFile().isWritable()) return false;
351-
355+
PsiFile psiFile = getPsiFile();
352356
Document document = getDocument();
353357

358+
if (psiFile == null || !psiFile.isWritable() || document == null || !document.isWritable()) return false;
359+
354360
ApplicationManager.getApplication().runWriteAction(() -> {
355361
CommandProcessor.getInstance().executeCommand(
356362
getPsiFile().getProject(),
@@ -406,18 +412,20 @@ private static class AddSiblingPsiAction extends PsiAction {
406412
private final PsiElement myElementToAdd;
407413
private final boolean myBefore;
408414

409-
AddSiblingPsiAction(@NotNull PsiElement anchor, @NotNull PsiElement elementToAdd) {
415+
AddSiblingPsiAction(@NotNull PsiElement anchor, @Nullable PsiElement elementToAdd) {
410416
this(anchor, elementToAdd, false);
411417
}
412418

413-
AddSiblingPsiAction(@NotNull PsiElement anchor, @NotNull PsiElement elementToAdd, boolean before) {
419+
AddSiblingPsiAction(@NotNull PsiElement anchor, @Nullable PsiElement elementToAdd, boolean before) {
414420
super(anchor);
415421
myElementToAdd = elementToAdd;
416422
myBefore = before;
417423
}
418424

419425
@Override
420426
public void execute() {
427+
if (myElementToAdd == null) return;
428+
421429
PsiElement anchor = getAnchor();
422430
if (anchor.getParent() == null) return;
423431
if (myBefore) {
@@ -432,13 +440,15 @@ private static class AddChildPsiAction extends PsiAction {
432440

433441
private final PsiElement myElementToAdd;
434442

435-
AddChildPsiAction(@NotNull PsiElement parent, @NotNull PsiElement elementToAdd) {
443+
AddChildPsiAction(@NotNull PsiElement parent, @Nullable PsiElement elementToAdd) {
436444
super(parent);
437445
myElementToAdd = elementToAdd;
438446
}
439447

440448
@Override
441449
public void execute() {
450+
if (myElementToAdd == null) return;
451+
442452
PsiElement anchor = getAnchor();
443453
anchor.add(myElementToAdd);
444454
}
@@ -448,13 +458,15 @@ private static class ReplacePsiAction extends PsiAction {
448458

449459
private final PsiElement myReplacement;
450460

451-
ReplacePsiAction(@NotNull PsiElement anchor, @NotNull PsiElement replacement) {
461+
ReplacePsiAction(@NotNull PsiElement anchor, @Nullable PsiElement replacement) {
452462
super(anchor);
453463
myReplacement = replacement;
454464
}
455465

456466
@Override
457467
public void execute() {
468+
if (myReplacement == null) return;
469+
458470
getAnchor().replace(myReplacement);
459471
}
460472
}
@@ -503,6 +515,8 @@ public void execute() {
503515

504516
PsiDocumentManager manager = PsiDocumentManager.getInstance(psiFile.getProject());
505517
Document document = manager.getDocument(psiFile);
518+
if (document == null) return;
519+
506520
manager.doPostponedOperationsAndUnblockDocument(document);
507521

508522
int offset = 0;

src/main/java/net/seesharpsoft/intellij/psi/PsiHelper.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public static PsiElement getLastSiblingOfType(@NotNull final PsiElement element,
103103
return prevSibling == element ? null : prevSibling;
104104
}
105105

106-
public static PsiElement findFirst(@NotNull final PsiElement root, @NotNull IElementType type) {
106+
public static PsiElement findFirst(@Nullable final PsiElement root, @NotNull IElementType type) {
107107
return SyntaxTraverser.psiTraverser(root).filterTypes(elementType -> elementType == type).filter(PsiElement.class).first();
108108
}
109109

src/main/java/net/seesharpsoft/intellij/util/Suspendable.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ default void dispose() {
2828
class SuspensionMonitor {
2929
private final Map<Suspendable, Integer> suspendableCounterMap = new ConcurrentHashMap<>();
3030

31-
private Integer getSuspendableCounter(Suspendable suspendable) {
31+
private synchronized Integer getSuspendableCounter(Suspendable suspendable) {
3232
if (suspendableCounterMap.containsKey(suspendable)) return suspendableCounterMap.get(suspendable);
3333
return null;
3434
}

0 commit comments

Comments
 (0)