mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-50496 Spellchecker doesn't honor character escapes in Java/Groovy string literals
This commit is contained in:
+22
-10
@@ -16,10 +16,10 @@
|
||||
package org.jetbrains.plugins.groovy.codeInspection.spellchecker;
|
||||
|
||||
import com.intellij.codeInspection.SuppressIntentionAction;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.javadoc.PsiDocComment;
|
||||
import com.intellij.spellchecker.inspections.PlainTextSplitter;
|
||||
import com.intellij.spellchecker.tokenizer.EscapeSequenceTokenizer;
|
||||
import com.intellij.spellchecker.tokenizer.SuppressibleSpellcheckingStrategy;
|
||||
import com.intellij.spellchecker.tokenizer.TokenConsumer;
|
||||
import com.intellij.spellchecker.tokenizer.Tokenizer;
|
||||
@@ -27,31 +27,43 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.groovy.codeInspection.GroovySuppressableInspectionTool;
|
||||
import org.jetbrains.plugins.groovy.lang.lexer.TokenSets;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrNamedElement;
|
||||
import org.jetbrains.plugins.groovy.lang.resolve.GroovyStringLiteralManipulator;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class GroovySpellcheckingStrategy extends SuppressibleSpellcheckingStrategy {
|
||||
private final GrDocCommentTokenizer myDocCommentTokenizer = new GrDocCommentTokenizer();
|
||||
private Tokenizer<PsiElement> myStringTokenizer = new Tokenizer<PsiElement>() {
|
||||
@Override
|
||||
public void tokenize(@NotNull PsiElement literal, TokenConsumer consumer) {
|
||||
String text = GrStringUtil.removeQuotes(literal.getText());
|
||||
if (!text.contains("\\")) {
|
||||
consumer.consumeToken(literal, PlainTextSplitter.getInstance());
|
||||
}
|
||||
else {
|
||||
StringBuilder unescapedText = new StringBuilder();
|
||||
int[] offsets = new int[text.length() + 1];
|
||||
GrStringUtil.parseStringCharacters(text, unescapedText, offsets);
|
||||
EscapeSequenceTokenizer.processTextWithOffsets(literal, consumer, unescapedText, offsets, GrStringUtil.getStartQuote(literal.getText()).length());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Tokenizer getTokenizer(PsiElement element) {
|
||||
if (TokenSets.STRING_LITERAL_SET.contains(element.getNode().getElementType())) {
|
||||
return myStringTokenizer;
|
||||
}
|
||||
if (element instanceof GrNamedElement) {
|
||||
final PsiElement name = ((GrNamedElement)element).getNameIdentifierGroovy();
|
||||
if (TokenSets.STRING_LITERAL_SET.contains(name.getNode().getElementType())) {
|
||||
return new Tokenizer<GrNamedElement>() {
|
||||
@Override
|
||||
public void tokenize(@NotNull GrNamedElement element, TokenConsumer consumer) {
|
||||
String text = name.getText();
|
||||
TextRange range = GroovyStringLiteralManipulator.getLiteralRange(text);
|
||||
consumer.consumeToken(name, text, false, 0, range, PlainTextSplitter.getInstance());
|
||||
}
|
||||
};
|
||||
return EMPTY_TOKENIZER;
|
||||
}
|
||||
}
|
||||
if (element instanceof PsiDocComment) return myDocCommentTokenizer;
|
||||
//if (element instanceof GrLiteralImpl && ((GrLiteralImpl)element).isStringLiteral()) return myStringTokenizer;
|
||||
return super.getTokenizer(element);
|
||||
}
|
||||
|
||||
|
||||
+11
-1
@@ -45,5 +45,15 @@ class SpockTest {
|
||||
'''
|
||||
checkTypos()
|
||||
}
|
||||
|
||||
|
||||
public void testStringEscapes() {
|
||||
myFixture.configureByText 'a.groovy', '''
|
||||
def foo = "\\ntest \\n<TYPO descr="Typo: In word 'dddd'">dddd</TYPO>"
|
||||
def foo1 = '\\ntest \\n<TYPO descr="Typo: In word 'dddd'">dddd</TYPO>'
|
||||
def bar = """\\ntest \\n<TYPO descr="Typo: In word 'dddd'">dddd</TYPO>"""
|
||||
def bar1 = \'''\\ntest \\n<TYPO descr="Typo: In word 'dddd'">dddd</TYPO>\'''
|
||||
'''
|
||||
checkTypos()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -64,6 +64,6 @@ public class LiteralExpressionTokenizer extends Tokenizer<PsiLiteralExpression>
|
||||
int[] offsets = new int[text.length()+1];
|
||||
PsiLiteralExpressionImpl.parseStringCharacters(text, unescapedText, offsets);
|
||||
|
||||
EscapeSequenceTokenizer.processTextWithOffsets(element, consumer, unescapedText, offsets);
|
||||
EscapeSequenceTokenizer.processTextWithOffsets(element, consumer, unescapedText, offsets, 1);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -24,13 +24,13 @@ import com.intellij.spellchecker.inspections.PlainTextSplitter;
|
||||
*/
|
||||
public class EscapeSequenceTokenizer {
|
||||
public static void processTextWithOffsets(PsiElement element, TokenConsumer consumer, StringBuilder unescapedText,
|
||||
int[] offsets) {
|
||||
int[] offsets, int startOffset) {
|
||||
StringBuilder currentToken = new StringBuilder();
|
||||
int currentTokenStart = 0;
|
||||
int currentTokenStart = startOffset;
|
||||
for (int i = 0; i < unescapedText.length(); i++) {
|
||||
if (offsets[i+1]-offsets[i] == 1) {
|
||||
if (currentToken.length() == 0) {
|
||||
currentTokenStart = offsets[i];
|
||||
currentTokenStart = offsets[i] + startOffset;
|
||||
}
|
||||
currentToken.append(unescapedText.charAt(i));
|
||||
}
|
||||
@@ -51,6 +51,6 @@ public class EscapeSequenceTokenizer {
|
||||
int currentTokenStart, TokenConsumer consumer) {
|
||||
final String token = currentToken.toString();
|
||||
// +1 for the starting quote of the string literal
|
||||
consumer.consumeToken(element, token, false, currentTokenStart+1, TextRange.allOf(token), PlainTextSplitter.getInstance());
|
||||
consumer.consumeToken(element, token, false, currentTokenStart, TextRange.allOf(token), PlainTextSplitter.getInstance());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user