Skip to content

Commit

Permalink
Prevent NPE when analyzing natural language text in IntelliJ 2022.3 (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
ahus1 committed Oct 23, 2022
1 parent 5b1606c commit 8a4911f
Show file tree
Hide file tree
Showing 27 changed files with 94 additions and 107 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ This document provides a high-level view of the changes introduced by release.

=== 0.37.53

- Prevent NPE when analyzing natural language text (#1204)

=== 0.37.53

- Allow ID attribute on all macros, for example on images
- Resolve `+++file:///+++` URIs to local files when auto-completing in the editor.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ protected void selectText(Editor editor) {
PsiFile psiFile = PsiDocumentManager.getInstance(editor.getProject()).getPsiFile(editor.getDocument());
if (psiFile != null) {
PsiElement statementAtCaret = AsciiDocUtil.getStatementAtCaret(editor, psiFile);
if (statementAtCaret != null && (statementAtCaret.getNode().getElementType() == AsciiDocTokenTypes.URL_LINK
if (statementAtCaret != null && statementAtCaret.getNode() != null && (statementAtCaret.getNode().getElementType() == AsciiDocTokenTypes.URL_LINK
|| statementAtCaret.getNode().getElementType() == AsciiDocTokenTypes.URL_EMAIL)) {
int start = statementAtCaret.getTextOffset();
int end = statementAtCaret.getTextOffset() + statementAtCaret.getTextLength();
Expand Down Expand Up @@ -124,7 +124,7 @@ private boolean isLink(Editor editor) {
PsiFile psiFile = PsiDocumentManager.getInstance(editor.getProject()).getPsiFile(editor.getDocument());
if (psiFile != null) {
PsiElement statementAtCaret = psiFile.findElementAt(editor.getSelectionModel().getSelectionStart());
return statementAtCaret != null && statementAtCaret.getNode().getElementType() == AsciiDocTokenTypes.URL_LINK;
return statementAtCaret != null && statementAtCaret.getNode() != null && statementAtCaret.getNode().getElementType() == AsciiDocTokenTypes.URL_LINK;
}
}
return false;
Expand All @@ -135,7 +135,7 @@ private boolean isEmail(Editor editor) {
PsiFile psiFile = PsiDocumentManager.getInstance(editor.getProject()).getPsiFile(editor.getDocument());
if (psiFile != null) {
PsiElement statementAtCaret = psiFile.findElementAt(editor.getSelectionModel().getSelectionStart());
return statementAtCaret != null && statementAtCaret.getNode().getElementType() == AsciiDocTokenTypes.URL_EMAIL;
return statementAtCaret != null && statementAtCaret.getNode() != null && statementAtCaret.getNode().getElementType() == AsciiDocTokenTypes.URL_EMAIL;
}
}
return false;
Expand All @@ -147,9 +147,9 @@ private void removeUrlStartEnd(Editor editor) {
PsiDocumentManager.getInstance(editor.getProject()).doPostponedOperationsAndUnblockDocument(editor.getDocument());
if (psiFile != null) {
PsiElement statementAtCaret = psiFile.findElementAt(editor.getSelectionModel().getSelectionStart());
if (statementAtCaret != null && statementAtCaret.getNode().getElementType() == AsciiDocTokenTypes.URL_LINK) {
if (statementAtCaret.getPrevSibling() != null && statementAtCaret.getPrevSibling().getNode().getElementType() == AsciiDocTokenTypes.URL_START
&& statementAtCaret.getNextSibling() != null && statementAtCaret.getNextSibling().getNode().getElementType() == AsciiDocTokenTypes.URL_END) {
if (statementAtCaret != null && statementAtCaret.getNode() != null && statementAtCaret.getNode().getElementType() == AsciiDocTokenTypes.URL_LINK) {
if (statementAtCaret.getPrevSibling() != null && statementAtCaret.getPrevSibling().getNode() != null && statementAtCaret.getPrevSibling().getNode().getElementType() == AsciiDocTokenTypes.URL_START
&& statementAtCaret.getNextSibling() != null && statementAtCaret.getNextSibling().getNode() != null && statementAtCaret.getNextSibling().getNode().getElementType() == AsciiDocTokenTypes.URL_END) {
statementAtCaret.getPrevSibling().delete();
statementAtCaret.getNextSibling().delete();
PsiDocumentManager.getInstance(editor.getProject()).doPostponedOperationsAndUnblockDocument(editor.getDocument());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public static AsciiDocSection getSectionWithoutBlockIdAtCursor(PsiFile file, Edi
return null;
}
}
if (statementAtCaret.getNode().getElementType() == AsciiDocTokenTypes.HEADING_TOKEN) {
if (statementAtCaret.getNode() != null && statementAtCaret.getNode().getElementType() == AsciiDocTokenTypes.HEADING_TOKEN) {
statementAtCaret = statementAtCaret.getParent();
}
if (!(statementAtCaret instanceof AsciiDocSection)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file
if (statementAtCaret == null) {
return false;
}
if (statementAtCaret.getNode().getElementType() != AsciiDocTokenTypes.ADMONITION) {
if (statementAtCaret.getNode() != null && statementAtCaret.getNode().getElementType() != AsciiDocTokenTypes.ADMONITION) {
return false;
}
return true;
Expand All @@ -40,7 +40,7 @@ public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws
if (statementAtCaret == null) {
return;
}
if (statementAtCaret.getNode().getElementType() != AsciiDocTokenTypes.ADMONITION) {
if (statementAtCaret.getNode() != null && statementAtCaret.getNode().getElementType() != AsciiDocTokenTypes.ADMONITION) {
return;
}
PsiElement loop = statementAtCaret.getNextSibling();
Expand All @@ -66,7 +66,7 @@ public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws
} else {
onNewLine = false;
}
if (loop instanceof AsciiDocBlock || loop.getNode().getElementType() == AsciiDocTokenTypes.CONTINUATION) {
if (loop instanceof AsciiDocBlock || (loop.getNode() != null && loop.getNode().getElementType() == AsciiDocTokenTypes.CONTINUATION)) {
break;
}
buffer.append(loop.getText());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public void beforeCompletion(@NotNull CompletionInitializationContext context) {

int offset = context.getStartOffset();
PsiElement element = context.getFile().findElementAt(offset);
if (element != null) {
if (element != null && element.getNode() != null) {
if (element.getNode().getElementType() == AsciiDocTokenTypes.ATTRIBUTE_NAME) {
// the identifier end offset needs to be set as otherwise an id containing a "-" will not be replaced
context.getOffsetMap().addOffset(CompletionInitializationContext.IDENTIFIER_END_OFFSET, element.getTextOffset() + element.getTextLength());
Expand All @@ -47,8 +47,8 @@ public void beforeCompletion(@NotNull CompletionInitializationContext context) {
if (element.getNode().getElementType() == AsciiDocTokenTypes.ATTRIBUTE_REF) {
PsiElement parent = element.getParent().getParent();
// help the autocomplete in AsciiDocFileReference to replace the full reference if it contains a nested attribute
if (parent.getNode().getElementType() == AsciiDocElementTypes.BLOCK_MACRO || parent.getNode().getElementType() == AsciiDocElementTypes.INLINE_MACRO
|| parent.getNode().getElementType() == AsciiDocElementTypes.ATTRIBUTE_IN_BRACKETS) {
if (parent.getNode() != null && (parent.getNode().getElementType() == AsciiDocElementTypes.BLOCK_MACRO || parent.getNode().getElementType() == AsciiDocElementTypes.INLINE_MACRO
|| parent.getNode().getElementType() == AsciiDocElementTypes.ATTRIBUTE_IN_BRACKETS)) {
for (PsiReference reference : parent.getReferences()) {
if (reference.getRangeInElement().shiftRight(parent.getTextOffset()).contains(element.getTextRange())) {
context.getOffsetMap().addOffset(IDENTIFIER_FILE_REFERENCE, parent.getTextOffset() + reference.getRangeInElement().getEndOffset());
Expand All @@ -61,7 +61,7 @@ public void beforeCompletion(@NotNull CompletionInitializationContext context) {

public AsciiDocCompletionContributor() {
extend(CompletionType.BASIC, PlatformPatterns.psiElement().withElementType(AsciiDocTokenTypes.ATTRIBUTE_NAME).withLanguage(AsciiDocLanguage.INSTANCE),
new CompletionProvider<CompletionParameters>() {
new CompletionProvider<>() {
@Override
public void addCompletions(@NotNull CompletionParameters parameters, @NotNull ProcessingContext processingContext,
@NotNull CompletionResultSet resultSet) {
Expand All @@ -75,7 +75,7 @@ public void addCompletions(@NotNull CompletionParameters parameters, @NotNull Pr
int offset = insertionContext.getStartOffset();
PsiElement element = insertionContext.getFile().findElementAt(offset);
if (element != null) {
if (element.getNode().getElementType() != AsciiDocTokenTypes.ATTRIBUTE_NAME) {
if (element.getNode() != null && element.getNode().getElementType() != AsciiDocTokenTypes.ATTRIBUTE_NAME) {
// the finalizing : hasn't been entered yet, autocomplete it here
offset += attribute.length();
insertionContext.getDocument().insertString(offset, ":");
Expand All @@ -94,7 +94,7 @@ public void addCompletions(@NotNull CompletionParameters parameters, @NotNull Pr
}
});
extend(CompletionType.BASIC, PlatformPatterns.psiElement().withElementType(AsciiDocTokenTypes.ATTR_VALUE).withLanguage(AsciiDocLanguage.INSTANCE),
new CompletionProvider<CompletionParameters>() {
new CompletionProvider<>() {
@Override
public void addCompletions(@NotNull CompletionParameters parameters, @NotNull ProcessingContext processingContext,
@NotNull CompletionResultSet resultSet) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@

/**
* Suggest word selections to the editor.
* See {@link com.intellij.codeInsight.editorActions.wordSelection.NaturalLanguageTextSelectioner}
* See <code>com.intellij.codeInsight.editorActions.wordSelection.NaturalLanguageTextSelectioner</code>
* for more ideas.
*/
public class ExtendWordSelectionHandler extends ExtendWordSelectionHandlerBase {
Expand Down Expand Up @@ -100,15 +100,15 @@ public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence edito

// expand start/endFormatting within paragraph
while (startFormatting != null && endFormatting != null) {
while (startFormatting != null &&
while (startFormatting != null && startFormatting.getNode() != null &&
!SYMMETRIC_FORMATTING.containsKey(startFormatting.getNode().getElementType()) &&
!startFormatting.getText().contains("\n")) {
startFormatting = startFormatting.getPrevSibling();
}
if (startFormatting == null) {
break;
}
while (endFormatting != null &&
while (endFormatting != null && startFormatting.getNode() != null &&
SYMMETRIC_FORMATTING.get(startFormatting.getNode().getElementType()) != endFormatting.getNode().getElementType() &&
!endFormatting.getText().contains("\n")) {
endFormatting = endFormatting.getNextSibling();
Expand All @@ -124,7 +124,7 @@ public List<TextRange> select(@NotNull PsiElement e, @NotNull CharSequence edito
if (endFormatting instanceof PsiWhiteSpace && endFormatting.getText().contains("\n")) {
endOffset = -endFormatting.getTextLength() + endFormatting.getText().indexOf("\n");
}
if (SYMMETRIC_FORMATTING.get(startFormatting.getNode().getElementType()) == endFormatting.getNode().getElementType()) {
if (startFormatting.getNode() != null && SYMMETRIC_FORMATTING.get(startFormatting.getNode().getElementType()) == endFormatting.getNode().getElementType()) {
// we might be looking at the identical token (for example a double quote) for start and end,
// prevent to report this with its end first and start second, which would lead to an inverse and icorrect range
if (startFormatting.getTextRange().getEndOffset() < endFormatting.getTextRange().getStartOffset()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public String getDescriptiveName(@NotNull PsiElement element) {
name = "???";
}
} else {
name = "??? " + element.getNode().getElementType();
name = "??? " + (element.getNode() != null ? element.getNode().getElementType() : element.getClass().getName());
}
return name;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar)
context) {
int start = 0;
PsiElement child = element.getFirstChild();
while (child != null && child.getNode().getElementType() != AsciiDocTokenTypes.ATTRIBUTE_REF) {
while (child != null && child.getNode() != null && child.getNode().getElementType() != AsciiDocTokenTypes.ATTRIBUTE_REF) {
start += child.getTextLength();
child = child.getNextSibling();
}
Expand Down Expand Up @@ -130,7 +130,7 @@ private List<PsiReference> findFilesInProject(AsciiDocTextQuoted element) {
}

private List<PsiReference> findFileReferences(PsiElement element) {
if (element.getNode().findChildByType(AsciiDocTokenTypes.URL_LINK) != null) {
if (element.getNode() != null && element.getNode().findChildByType(AsciiDocTokenTypes.URL_LINK) != null) {
return Collections.emptyList();
}
if (element.getChildren().length > 0 && element.getChildren()[0] instanceof AsciiDocAttributeReference) {
Expand Down Expand Up @@ -217,7 +217,7 @@ private List<PsiReference> findFileReferences(PsiElement element) {

private List<PsiReference> findUrlReferencesInLinks(PsiElement element) {
PsiElement child = element.getFirstChild();
while (child != null && child.getNode().getElementType() != AsciiDocTokenTypes.URL_LINK) {
while (child != null && child.getNode() != null && child.getNode().getElementType() != AsciiDocTokenTypes.URL_LINK) {
child = child.getNextSibling();
}
if (child != null) {
Expand Down Expand Up @@ -250,7 +250,7 @@ private List<PsiReference> findTagInDocument(AsciiDocIncludeTagInDocument elemen
private List<PsiReference> findUrlReferencesInAttributeDefinition(PsiElement element) {
PsiElement child = element.getFirstChild();
List<PsiReference> result = new ArrayList<>();
while (child != null && child.getNode().getElementType() != AsciiDocTokenTypes.ATTRIBUTE_VAL) {
while (child != null && child.getNode() != null && child.getNode().getElementType() != AsciiDocTokenTypes.ATTRIBUTE_VAL) {
child = child.getNextSibling();
}
if (child != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public void visitElement(@NotNull PsiElement element) {
}
} else if (element instanceof AsciiDocHtmlEntity) {
addDescriptors(element);
} else if (COLLAPSABLE_TYPES.containsKey(element.getNode().getElementType())) {
} else if (element.getNode() != null && COLLAPSABLE_TYPES.containsKey(element.getNode().getElementType())) {
addDescriptors(element);
}
super.visitElement(element);
Expand Down Expand Up @@ -147,7 +147,7 @@ private static void addDescriptors(@NotNull PsiElement element,
descriptors.add(new FoldingDescriptor(element, range));
} else if (element instanceof AsciiDocHtmlEntity) {
descriptors.add(new FoldingDescriptor(element, range));
} else if (COLLAPSABLE_TYPES.containsKey(element.getNode().getElementType())) {
} else if (element.getNode() != null && COLLAPSABLE_TYPES.containsKey(element.getNode().getElementType())) {
descriptors.add(new FoldingDescriptor(element, range));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public void visitElement(@NotNull PsiElement element) {
super.visitElement(element);
if (languageSupport.getElementBehavior(root, element) == AsciiDocLanguageSupport.Behavior.TEXT) {
int pos = element.getTextOffset();
if (element.getNode().getElementType() == AsciiDocTokenTypes.TYPOGRAPHIC_SINGLE_QUOTE_START
if (element.getNode() != null && element.getNode().getElementType() == AsciiDocTokenTypes.TYPOGRAPHIC_SINGLE_QUOTE_START
&& element.getTextLength() == 2) {
// ` at the end of '`
ranges.add(new TextRange(pos + 1, pos + 2));
Expand All @@ -100,30 +100,30 @@ public void visitElement(@NotNull PsiElement element) {
// AsciiDoc will eat extra spaces when rendering. Let's do the same here.
ranges.add(new TextRange(pos + 1, pos + element.getTextLength()));
}
if ((element.getNode().getElementType() == AsciiDocTokenTypes.ATTRIBUTE_CONTINUATION
if (element.getNode() != null && (element.getNode().getElementType() == AsciiDocTokenTypes.ATTRIBUTE_CONTINUATION
|| element.getNode().getElementType() == AsciiDocTokenTypes.ATTRIBUTE_CONTINUATION_LEGACY)
&& element.getTextLength() == 3) {
// this will strip out the '+' or '\' and the newline from the continuation before forwarding it to the grammar check
ranges.add(new TextRange(pos + 1, pos + 3));
}
if ((element.getNode().getElementType() == AsciiDocTokenTypes.DESCRIPTION_END)) {
if (element.getNode() != null && element.getNode().getElementType() == AsciiDocTokenTypes.DESCRIPTION_END) {
// this will strip the duplicated characters
ranges.add(new TextRange(pos, pos + element.getTextLength() - 1));
}
if (element.getNode().getElementType() == AsciiDocTokenTypes.TYPOGRAPHIC_SINGLE_QUOTE_END
if (element.getNode() != null && element.getNode().getElementType() == AsciiDocTokenTypes.TYPOGRAPHIC_SINGLE_QUOTE_END
&& element.getTextLength() == 2) {
// ` at the beginning of `'
ranges.add(new TextRange(pos, pos + 1));
}
if (element.getNode().getElementType() == AsciiDocTokenTypes.HEADING_OLDSTYLE && element.getTextLength() >= 1) {
if (element.getNode() != null && element.getNode().getElementType() == AsciiDocTokenTypes.HEADING_OLDSTYLE && element.getTextLength() >= 1) {
// ignore second line of heading
String heading = element.getText();
int i = heading.indexOf('\n');
if (i != -1) {
ranges.add(new TextRange(pos + i, pos + heading.length()));
}
}
if (element.getNode().getElementType() == AsciiDocTokenTypes.HEADING_TOKEN && element.getTextLength() >= 1
if (element.getNode() != null && element.getNode().getElementType() == AsciiDocTokenTypes.HEADING_TOKEN && element.getTextLength() >= 1
&& element.getPrevSibling() == null) {
// ignore "##" or "==" at start of heading
String heading = element.getText();
Expand Down
Loading

0 comments on commit 8a4911f

Please sign in to comment.