java spellchecker: @NonNls suppresses spell checking when applied to method return type (IDEA-180639)

This commit is contained in:
Dmitry Batkovich
2017-12-04 12:42:51 +03:00
parent d223687f56
commit 0200fe3b9d
9 changed files with 92 additions and 20 deletions
@@ -3,17 +3,19 @@ package com.intellij.spellchecker;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.PsiLiteralExpression;
import com.intellij.psi.PsiModifierListOwner;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.spellchecker.inspections.PlainTextSplitter;
import com.intellij.spellchecker.tokenizer.EscapeSequenceTokenizer;
import com.intellij.spellchecker.tokenizer.TokenConsumer;
import com.siyeh.ig.psiutils.ExpressionUtils;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
/**
* @author shkate@jetbrains.com
*/
@@ -31,7 +33,15 @@ public class LiteralExpressionTokenizer extends EscapeSequenceTokenizer<PsiLiter
final PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(element, PsiModifierListOwner.class);
if (listOwner != null && AnnotationUtil.isAnnotated(listOwner, AnnotationUtil.NON_NLS, AnnotationUtil.CHECK_EXTERNAL)) {
return;
PsiElement targetElement = getCompleteStringValueExpression(element);
if (listOwner instanceof PsiMethod) {
if (Arrays.stream(PsiUtil.findReturnStatements(((PsiMethod)listOwner))).map(s -> s.getReturnValue()).anyMatch(e -> e == targetElement)) {
return;
}
}
else if (listOwner instanceof PsiVariable && ((PsiVariable)listOwner).getInitializer() == targetElement) {
return;
}
}
if (!text.contains("\\")) {
@@ -44,9 +54,13 @@ public class LiteralExpressionTokenizer extends EscapeSequenceTokenizer<PsiLiter
public static void processTextWithEscapeSequences(PsiLiteralExpression element, String text, TokenConsumer consumer) {
StringBuilder unescapedText = new StringBuilder();
int[] offsets = new int[text.length()+1];
int[] offsets = new int[text.length() + 1];
PsiLiteralExpressionImpl.parseStringCharacters(text, unescapedText, offsets);
processTextWithOffsets(element, consumer, unescapedText, offsets, 1);
}
public static PsiElement getCompleteStringValueExpression(PsiExpression expression) {
return ExpressionUtils.isStringConcatenationOperand(expression) ? expression.getParent() : expression;
}
}
@@ -0,0 +1,8 @@
import org.jetbrains.annotations.NonNls;
class Test {
/**
* <TYPO descr="Typo: In word 'CONASTANT'">CONASTANT</TYPO>
*/
@NonNls String s = "";
}
@@ -0,0 +1,9 @@
import org.jetbrains.annotations.NonNls;
class Test {
@NonNls
public String foo() {
System.out.println("<TYPO descr="Typo: In word 'CONASTANT'">CONASTANT</TYPO>");
return null;
}
}
@@ -0,0 +1,8 @@
import org.jetbrains.annotations.NonNls;
class Test {
@NonNls
public String foo() {
return "CONASTANT";
}
}
@@ -0,0 +1,5 @@
import org.jetbrains.annotations.NonNls;
class Test {
@NonNls String s = "CONASTANT";
}
@@ -0,0 +1,9 @@
import org.jetbrains.annotations.NonNls;
class Test {
@NonNls String s = getValue("<TYPO descr="Typo: In word 'CONASTANT'">CONASTANT</TYPO>");
String getValue(String key) {
return null;
}
}
@@ -0,0 +1,7 @@
import org.jetbrains.annotations.NonNls;
class Test {
void m() {
@NonNls String s = "CONASTANT" + " some " + " text " + " concatenation ";
}
}
@@ -0,0 +1,7 @@
import org.jetbrains.annotations.NonNls;
class Test {
void m() {
@NonNls String s = "CONASTANT"; // <TYPO descr="Typo: In word 'CONASTANT'">CONASTANT</TYPO> comment
}
}
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.spellchecker.inspection;
import com.intellij.openapi.application.PluginPathManager;
@@ -24,6 +10,16 @@ public class JavaSpellcheckerInspectionTest extends LightCodeInsightFixtureTestC
return PluginPathManager.getPluginHomePathRelative("java-i18n") + "/testData/inspections/spellchecker";
}
@Override
public void setUp() throws Exception {
super.setUp();
myFixture.addClass("package org.jetbrains.annotations;" +
"import java.lang.annotation.*;" +
"@Retention(RetentionPolicy.CLASS)" +
"@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.TYPE, ElementType.PACKAGE})" +
"public @interface NonNls {}");
}
public void testCorrectJava() { doTest(); }
public void testTypoInJava() { doTest(); }
public void testVarArg() { doTest(); }
@@ -38,6 +34,15 @@ public class JavaSpellcheckerInspectionTest extends LightCodeInsightFixtureTestC
public void testStringLiteralEscaping() { doTest(); }
public void testSuppressions() { doTest(); }
// suppression by @NonNls
public void testMethodReturnTypeWithNonNls() { doTest(); }
public void testMethodReturnTypeWithNonNlsReturnsLiteral() { doTest(); }
public void testNonNlsField() { doTest(); }
public void testNonNlsField2() { doTest(); }
public void testNonNlsLocalVariable() { doTest(); }
public void testNonNlsLocalVariableAndComment() { doTest(); }
public void testFieldComment() { doTest(); }
private void doTest() {
myFixture.enableInspections(SpellcheckerInspectionTestCase.getInspectionTools());
myFixture.testHighlighting(false, false, true, getTestName(false) + ".java");