diff --git a/json/backend/tests/test/com/intellij/json/JsonSpellcheckerTest.java b/json/backend/tests/test/com/intellij/json/JsonSpellcheckerTest.java
index ce37e291dc9d..433859420856 100644
--- a/json/backend/tests/test/com/intellij/json/JsonSpellcheckerTest.java
+++ b/json/backend/tests/test/com/intellij/json/JsonSpellcheckerTest.java
@@ -1,6 +1,7 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.json;
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection;
import com.intellij.json.json5.Json5FileType;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.IdeActions;
@@ -8,7 +9,6 @@ import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
-import com.intellij.spellchecker.inspections.SpellCheckingInspection;
import com.intellij.testFramework.ServiceContainerUtil;
import com.intellij.testFramework.fixtures.InjectionTestFixture;
import com.jetbrains.jsonSchema.JsonSchemaTestProvider;
@@ -24,7 +24,7 @@ import java.util.function.Predicate;
public class JsonSpellcheckerTest extends JsonTestCase {
private void doTest() {
- myFixture.enableInspections(SpellCheckingInspection.class);
+ myFixture.enableInspections(GrazieSpellCheckingInspection.class);
myFixture.configureByFile(getTestName(false) + ".json");
myFixture.checkHighlighting(true, false, true);
}
@@ -52,14 +52,14 @@ public class JsonSpellcheckerTest extends JsonTestCase {
JsonSchemaTestServiceImpl.setProvider(null);
}
});
- myFixture.enableInspections(SpellCheckingInspection.class);
+ myFixture.enableInspections(GrazieSpellCheckingInspection.class);
myFixture.checkHighlighting(true, false, true);
}
// WEB-31894 EA-117068
public void testAfterModificationOfStringLiteralWithEscaping() {
myFixture.configureByFile(getTestName(false) + ".json");
- myFixture.enableInspections(SpellCheckingInspection.class);
+ myFixture.enableInspections(GrazieSpellCheckingInspection.class);
myFixture.checkHighlighting();
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_BACKSPACE);
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_BACKSPACE);
@@ -67,7 +67,7 @@ public class JsonSpellcheckerTest extends JsonTestCase {
}
public void testHashesQuotedSpelling() {
- myFixture.enableInspections(SpellCheckingInspection.class);
+ myFixture.enableInspections(GrazieSpellCheckingInspection.class);
myFixture.configureByText("hashes.json", """
{
"typo": "hereistheerror",
@@ -83,7 +83,7 @@ public class JsonSpellcheckerTest extends JsonTestCase {
}
public void testInjectedFragments() {
- myFixture.enableInspections(SpellCheckingInspection.class);
+ myFixture.enableInspections(GrazieSpellCheckingInspection.class);
myFixture.configureByText(Json5FileType.INSTANCE, """
{
diff --git a/platform/analysis-impl/resources/com/intellij/codeInspection/inspection-black-list.txt b/platform/analysis-impl/resources/com/intellij/codeInspection/inspection-black-list.txt
index b6af62adeb15..1a8eca07f393 100644
--- a/platform/analysis-impl/resources/com/intellij/codeInspection/inspection-black-list.txt
+++ b/platform/analysis-impl/resources/com/intellij/codeInspection/inspection-black-list.txt
@@ -17,13 +17,13 @@ com.intellij.codeInspection.uncheckedWarnings.UncheckedWarningLocalInspection
com.intellij.codeInspection.unusedSymbol.UnusedSymbolLocalInspection
com.intellij.codeInspection.varScopeCanBeNarrowed.FieldCanBeLocalInspection
com.intellij.codeInspection.visibility.VisibilityInspection
+com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection
com.intellij.lang.javascript.inspections.JSMismatchedCollectionQueryUpdateInspection
com.intellij.lang.javascript.inspections.JSPotentiallyInvalidConstructorUsageInspection
com.intellij.lang.javascript.inspections.JSSuspiciousNameCombinationInspection
com.intellij.lang.javascript.inspections.UnterminatedStatementJSInspection
com.intellij.psi.css.inspections.CssUnknownPropertyInspection
com.intellij.restructuredtext.python.inspections.RestRoleInspection
-com.intellij.spellchecker.inspections.SpellCheckingInspection
com.jetbrains.php.lang.inspections.PhpUndefinedClassInspection
com.jetbrains.php.lang.inspections.PhpUndefinedVariableInspection
com.jetbrains.php.lang.inspections.PhpUnusedParameterInspection
diff --git a/platform/platform-tests/BUILD.bazel b/platform/platform-tests/BUILD.bazel
index 9c2aff1a550d..e997f9429bd2 100644
--- a/platform/platform-tests/BUILD.bazel
+++ b/platform/platform-tests/BUILD.bazel
@@ -63,6 +63,7 @@ jvm_library(
"//platform/vcs-impl:vcs-impl_test_lib",
"//spellchecker",
"//spellchecker:spellchecker_test_lib",
+ "//plugins/grazie/src:core",
"@lib//:http-client",
"//jps/model-impl",
"@lib//:gson",
diff --git a/platform/platform-tests/intellij.platform.tests.iml b/platform/platform-tests/intellij.platform.tests.iml
index 2a9f59eda913..4978466bf0f6 100644
--- a/platform/platform-tests/intellij.platform.tests.iml
+++ b/platform/platform-tests/intellij.platform.tests.iml
@@ -51,6 +51,7 @@
+
diff --git a/platform/platform-tests/testSrc/com/intellij/codeHighlighting/CustomFileTypeInspectionTest.kt b/platform/platform-tests/testSrc/com/intellij/codeHighlighting/CustomFileTypeInspectionTest.kt
index 2c2596fdc06b..703b9007aa4f 100644
--- a/platform/platform-tests/testSrc/com/intellij/codeHighlighting/CustomFileTypeInspectionTest.kt
+++ b/platform/platform-tests/testSrc/com/intellij/codeHighlighting/CustomFileTypeInspectionTest.kt
@@ -1,7 +1,7 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeHighlighting
-import com.intellij.spellchecker.inspections.SpellCheckingInspection
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection
import com.intellij.testFramework.fixtures.BasePlatformTestCase
class CustomFileTypeInspectionTest : BasePlatformTestCase() {
@@ -15,7 +15,7 @@ infixl -- keyword
-- infixl in line comment
{- infixl in block comment -}
""")
- myFixture.enableInspections(SpellCheckingInspection())
+ myFixture.enableInspections(GrazieSpellCheckingInspection())
myFixture.checkHighlighting()
}
diff --git a/plugins/devkit/devkit-tests/BUILD.bazel b/plugins/devkit/devkit-tests/BUILD.bazel
index 4d10fa9db36c..4d49ae2fa474 100644
--- a/plugins/devkit/devkit-tests/BUILD.bazel
+++ b/plugins/devkit/devkit-tests/BUILD.bazel
@@ -35,6 +35,7 @@ jvm_library(
"//xml/xml-psi-api:psi",
"//spellchecker",
"//spellchecker:spellchecker_test_lib",
+ "//plugins/grazie/src:core",
]
)
### auto-generated section `build intellij.devkit.testFramework` end
diff --git a/plugins/devkit/devkit-tests/intellij.devkit.testFramework.iml b/plugins/devkit/devkit-tests/intellij.devkit.testFramework.iml
index db6490ecc788..391e92b2f4ac 100644
--- a/plugins/devkit/devkit-tests/intellij.devkit.testFramework.iml
+++ b/plugins/devkit/devkit-tests/intellij.devkit.testFramework.iml
@@ -26,6 +26,7 @@
+
\ No newline at end of file
diff --git a/plugins/devkit/devkit-tests/testSrc/org/jetbrains/idea/devkit/DevKitMnemonicsSpellingTest.kt b/plugins/devkit/devkit-tests/testSrc/org/jetbrains/idea/devkit/DevKitMnemonicsSpellingTest.kt
index b0b5c03145a5..f496d2298c2c 100644
--- a/plugins/devkit/devkit-tests/testSrc/org/jetbrains/idea/devkit/DevKitMnemonicsSpellingTest.kt
+++ b/plugins/devkit/devkit-tests/testSrc/org/jetbrains/idea/devkit/DevKitMnemonicsSpellingTest.kt
@@ -1,10 +1,10 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.idea.devkit
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection
import com.intellij.openapi.module.Module
import com.intellij.openapi.roots.ContentEntry
import com.intellij.openapi.roots.ModifiableRootModel
-import com.intellij.spellchecker.inspections.SpellCheckingInspection
import com.intellij.testFramework.LightProjectDescriptor
import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase
@@ -27,7 +27,7 @@ internal class DevKitMnemonicsSpellingTest : LightJavaCodeInsightFixtureTestCase
@Throws(Exception::class)
override fun setUp() {
super.setUp()
- myFixture.enableInspections(SpellCheckingInspection::class.java)
+ myFixture.enableInspections(GrazieSpellCheckingInspection::class.java)
}
fun testMnemonics() {
diff --git a/plugins/devkit/intellij.devkit.i18n/BUILD.bazel b/plugins/devkit/intellij.devkit.i18n/BUILD.bazel
index cd814b8f6d20..a2f2c83084c2 100644
--- a/plugins/devkit/intellij.devkit.i18n/BUILD.bazel
+++ b/plugins/devkit/intellij.devkit.i18n/BUILD.bazel
@@ -69,6 +69,7 @@ jvm_library(
"//java/testFramework",
"//spellchecker",
"//spellchecker:spellchecker_test_lib",
+ "//plugins/grazie/src:core",
"//platform/core-ui",
],
runtime_deps = [
diff --git a/plugins/devkit/intellij.devkit.i18n/intellij.devkit.i18n.iml b/plugins/devkit/intellij.devkit.i18n/intellij.devkit.i18n.iml
index 6bb19983eba0..69b8007df942 100644
--- a/plugins/devkit/intellij.devkit.i18n/intellij.devkit.i18n.iml
+++ b/plugins/devkit/intellij.devkit.i18n/intellij.devkit.i18n.iml
@@ -30,6 +30,7 @@
+
\ No newline at end of file
diff --git a/plugins/devkit/intellij.devkit.i18n/test/PluginXmlCapitalizationInspectionTest.java b/plugins/devkit/intellij.devkit.i18n/test/PluginXmlCapitalizationInspectionTest.java
index 2e1bc81631eb..2d562f14b0a2 100644
--- a/plugins/devkit/intellij.devkit.i18n/test/PluginXmlCapitalizationInspectionTest.java
+++ b/plugins/devkit/intellij.devkit.i18n/test/PluginXmlCapitalizationInspectionTest.java
@@ -2,8 +2,8 @@
package org.jetbrains.idea.devkit.i18n;
import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection;
import com.intellij.openapi.project.IntelliJProjectUtil;
-import com.intellij.spellchecker.inspections.SpellCheckingInspection;
import com.intellij.testFramework.TestDataPath;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
@@ -79,7 +79,7 @@ public class PluginXmlCapitalizationInspectionTest extends LightJavaCodeInsightF
" enum Capitalization {NotSpecified,Title,Sentence}" +
" Capitalization capitalization() default Capitalization.NotSpecified;" +
"}");
- myFixture.enableInspections(new SpellCheckingInspection());
+ myFixture.enableInspections(new GrazieSpellCheckingInspection());
myFixture.testHighlighting("pluginXmlCapitalization_extensionPoint.xml", "MyExtensionPoint.java");
}
}
diff --git a/plugins/grazie/resources/META-INF/plugin.xml b/plugins/grazie/resources/META-INF/plugin.xml
index 8f4ddfab071f..09be3aaa1e0c 100644
--- a/plugins/grazie/resources/META-INF/plugin.xml
+++ b/plugins/grazie/resources/META-INF/plugin.xml
@@ -67,6 +67,11 @@
implementationClass="com.intellij.grazie.ide.inspection.detection.LanguageDetectionInspection"
level="WEAK WARNING" key="grazie.detection.inspection.text" language=""/>
+
+
diff --git a/plugins/grazie/src/BUILD.bazel b/plugins/grazie/src/BUILD.bazel
index 6b4bdfc453d6..c05dce05a8a2 100644
--- a/plugins/grazie/src/BUILD.bazel
+++ b/plugins/grazie/src/BUILD.bazel
@@ -27,6 +27,7 @@ jvm_library(
"//platform/editor-ui-api:editor-ui",
"//platform/indexing-api:indexing",
"//platform/projectModel-api:projectModel",
+ "//platform/refactoring",
"//platform/vcs-api:vcs",
"//platform/editor-ui-ex:editor-ex",
"//platform/lang-api:lang",
diff --git a/plugins/grazie/src/intellij.grazie.core.iml b/plugins/grazie/src/intellij.grazie.core.iml
index 9c32cfd39966..cac1663bbdd3 100644
--- a/plugins/grazie/src/intellij.grazie.core.iml
+++ b/plugins/grazie/src/intellij.grazie.core.iml
@@ -22,6 +22,7 @@
+
diff --git a/plugins/grazie/src/main/kotlin/com/intellij/grazie/spellcheck/GrazieSpellCheckingInspection.java b/plugins/grazie/src/main/kotlin/com/intellij/grazie/spellcheck/GrazieSpellCheckingInspection.java
new file mode 100644
index 000000000000..10759fee4127
--- /dev/null
+++ b/plugins/grazie/src/main/kotlin/com/intellij/grazie/spellcheck/GrazieSpellCheckingInspection.java
@@ -0,0 +1,346 @@
+// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.grazie.spellcheck;
+
+import com.intellij.codeHighlighting.HighlightDisplayLevel;
+import com.intellij.codeInspection.*;
+import com.intellij.codeInspection.options.OptPane;
+import com.intellij.lang.LanguageNamesValidation;
+import com.intellij.lang.injection.InjectedLanguageManager;
+import com.intellij.lang.refactoring.NamesValidator;
+import com.intellij.openapi.progress.ProgressManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.TextRange;
+import com.intellij.openapi.util.registry.Registry;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.profile.codeInspection.InspectionProfileManager;
+import com.intellij.psi.*;
+import com.intellij.psi.util.CachedValuesManager;
+import com.intellij.refactoring.rename.RenameUtil;
+import com.intellij.spellchecker.SpellCheckerManager;
+import com.intellij.spellchecker.SpellCheckerSeveritiesProvider;
+import com.intellij.spellchecker.grazie.diacritic.Diacritics;
+import com.intellij.spellchecker.inspections.SpellCheckingInspection;
+import com.intellij.spellchecker.inspections.SpellcheckingExtension;
+import com.intellij.spellchecker.inspections.SpellcheckingExtension.SpellCheckingResult;
+import com.intellij.spellchecker.inspections.SpellcheckingExtension.SpellingTypo;
+import com.intellij.spellchecker.inspections.Splitter;
+import com.intellij.spellchecker.tokenizer.SpellcheckingStrategy;
+import com.intellij.spellchecker.tokenizer.SuppressibleSpellcheckingStrategy;
+import com.intellij.spellchecker.tokenizer.TokenConsumer;
+import com.intellij.spellchecker.util.SpellCheckerBundle;
+import com.intellij.util.Consumer;
+import com.intellij.util.containers.CollectionFactory;
+import com.intellij.util.text.StringSearcher;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import static com.intellij.codeInspection.options.OptPane.checkbox;
+import static com.intellij.codeInspection.options.OptPane.pane;
+import static com.intellij.spellchecker.tokenizer.SpellcheckingStrategy.getSpellcheckingStrategy;
+
+public final class GrazieSpellCheckingInspection extends SpellCheckingInspection {
+
+ @Override
+ public SuppressQuickFix @NotNull [] getBatchSuppressActions(@Nullable PsiElement element) {
+ if (element != null) {
+ SpellcheckingStrategy strategy = getSpellcheckingStrategy(element);
+ if (strategy instanceof SuppressibleSpellcheckingStrategy) {
+ return ((SuppressibleSpellcheckingStrategy)strategy).getSuppressActions(element, getShortName());
+ }
+ }
+ return super.getBatchSuppressActions(element);
+ }
+
+ @Override
+ public boolean isSuppressedFor(@NotNull PsiElement element) {
+ SpellcheckingStrategy strategy = getSpellcheckingStrategy(element);
+ if (strategy instanceof SuppressibleSpellcheckingStrategy) {
+ return ((SuppressibleSpellcheckingStrategy)strategy).isSuppressedFor(element, getShortName());
+ }
+ return super.isSuppressedFor(element);
+ }
+
+ @Override
+ public @NonNls @NotNull String getShortName() {
+ return SPELL_CHECKING_INSPECTION_TOOL_NAME;
+ }
+
+ @Override
+ public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
+ return super.buildVisitor(holder, isOnTheFly);
+ }
+
+ @Override
+ public @NotNull HighlightDisplayLevel getDefaultLevel() {
+ return Objects.requireNonNull(HighlightDisplayLevel.find(SpellCheckerSeveritiesProvider.TYPO));
+ }
+
+ @Override
+ public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder,
+ boolean isOnTheFly,
+ @NotNull LocalInspectionToolSession session) {
+ if (!Registry.is("spellchecker.inspection.enabled", true) ||
+ InspectionProfileManager.hasTooLowSeverity(session, this) ||
+ InjectedLanguageManager.getInstance(holder.getProject()).isFrankensteinInjection(holder.getFile())) {
+ return PsiElementVisitor.EMPTY_VISITOR;
+ }
+
+ var scopes = buildAllowedScopes();
+ SpellCheckerManager manager = SpellCheckerManager.getInstance(holder.getProject());
+ return new PsiElementVisitor() {
+ @Override
+ public void visitWhiteSpace(@NotNull PsiWhiteSpace space) { }
+
+ @Override
+ public void visitElement(final @NotNull PsiElement element) {
+ if (holder.getResultCount() > 1000 || element.getNode() == null) return;
+
+ var strategy = getSpellcheckingStrategy(element);
+ if (strategy == null || !strategy.elementFitsScope(element, scopes) || isCopyrightComment(strategy, element)) return;
+
+ SpellCheckingResult result = SpellcheckingExtension.Companion.spellcheck(
+ element, strategy, session,
+ typo -> {
+ if (hasSameNamedReferenceInFile(typo.getWord(), element, strategy)) return;
+ registerProblem(typo, holder);
+ }
+ );
+ if (result == SpellCheckingResult.Checked) return;
+
+ tokenize(
+ strategy, element,
+ new MyTokenConsumer(manager, strategy, holder, LanguageNamesValidation.INSTANCE.forLanguage(element.getLanguage())),
+ scopes
+ );
+ }
+ };
+ }
+
+ private Set buildAllowedScopes() {
+ var result = new HashSet();
+ if (processLiterals) {
+ result.add(SpellCheckingScope.Literals);
+ }
+ if (processComments) {
+ result.add(SpellCheckingScope.Comments);
+ }
+ if (processCode) {
+ result.add(SpellCheckingScope.Code);
+ }
+ return result;
+ }
+
+ private static void addBatchDescriptor(@NotNull PsiElement element,
+ @NotNull TextRange textRange,
+ @NotNull String word,
+ @NotNull ProblemsHolder holder) {
+ var fixes = SpellcheckingStrategy.getDefaultBatchFixes(element, textRange, word);
+ ProblemDescriptor problemDescriptor = createProblemDescriptor(element, textRange, fixes, false);
+ holder.registerProblem(problemDescriptor);
+ }
+
+ private static void addRegularDescriptor(@NotNull PsiElement element, @NotNull TextRange textRange, @NotNull ProblemsHolder holder,
+ boolean useRename, String wordWithTypo) {
+ SpellcheckingStrategy strategy = getSpellcheckingStrategy(element);
+
+ LocalQuickFix[] fixes = strategy != null
+ ? strategy.getRegularFixes(element, textRange, useRename, wordWithTypo)
+ : SpellcheckingStrategy.getDefaultRegularFixes(useRename, wordWithTypo, element, textRange);
+
+ final ProblemDescriptor problemDescriptor = createProblemDescriptor(element, textRange, fixes, true);
+ holder.registerProblem(problemDescriptor);
+ }
+
+ private static ProblemDescriptor createProblemDescriptor(PsiElement element, TextRange textRange,
+ LocalQuickFix[] fixes,
+ boolean onTheFly) {
+ final String description = SpellCheckerBundle.message("typo.in.word.ref");
+ return new ProblemDescriptorBase(element, element, description, fixes, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
+ false, textRange, onTheFly, onTheFly);
+ }
+
+ @SuppressWarnings("PublicField")
+ public boolean processCode = true;
+ public boolean processLiterals = true;
+ public boolean processComments = true;
+
+ @Override
+ public @NotNull OptPane getOptionsPane() {
+ return pane(
+ checkbox("processCode", SpellCheckerBundle.message("process.code")),
+ checkbox("processLiterals", SpellCheckerBundle.message("process.literals")),
+ checkbox("processComments", SpellCheckerBundle.message("process.comments"))
+ );
+ }
+
+ private static final class MyTokenConsumer extends TokenConsumer implements Consumer {
+ private static final Pattern NON_ENGLISH_LETTERS = Pattern.compile(".*[^a-zA-Z].*");
+
+ private final Set myAlreadyChecked = CollectionFactory.createSmallMemoryFootprintSet();
+ private final SpellCheckerManager myManager;
+ private final ProblemsHolder myHolder;
+ private final NamesValidator myNamesValidator;
+ private final SpellcheckingStrategy myStrategy;
+ private boolean myCodeLike;
+ private PsiElement myElement;
+ private String myText;
+ private boolean myUseRename;
+ private int myOffset;
+
+ MyTokenConsumer(SpellCheckerManager manager, SpellcheckingStrategy strategy, ProblemsHolder holder, NamesValidator namesValidator) {
+ myManager = manager;
+ myStrategy = strategy;
+ myHolder = holder;
+ myNamesValidator = namesValidator;
+ }
+
+ @Override
+ public void consumeToken(final PsiElement element,
+ final String text,
+ final boolean useRename,
+ final int offset,
+ TextRange rangeToCheck,
+ Splitter splitter) {
+ myElement = element;
+ myText = text;
+ myUseRename = useRename;
+ myOffset = offset;
+ myCodeLike = myStrategy.elementFitsScope(myElement, Set.of(SpellCheckingScope.Code));
+ splitter.split(text, rangeToCheck, this);
+ }
+
+ @Override
+ public void consume(TextRange range) {
+ // Tokenization of large texts can produce a lot of tokens, but we are inside RA
+ ProgressManager.checkCanceled();
+ String word = range.substring(myText);
+ if (!myHolder.isOnTheFly() && myAlreadyChecked.contains(word)) {
+ return;
+ }
+
+ boolean keyword = myNamesValidator.isKeyword(word, myElement.getProject());
+ if (keyword || !hasProblem(word, range) || hasSameNamedReferenceInFile(word, myElement, myStrategy)) {
+ return;
+ }
+
+ range = myStrategy.getTokenizer(myElement)
+ .getHighlightingRange(myElement, myOffset, range);
+ assert range.getStartOffset() >= 0;
+
+ if (!myHolder.isOnTheFly()) {
+ myAlreadyChecked.add(word);
+ }
+ registerProblem(myHolder, myElement, range, myUseRename, word);
+ }
+
+ private boolean hasCamelCaseMatch(String word, TextRange range) {
+ Set camelCaseWords = myManager.getUserCamelCaseWords()
+ .stream()
+ .filter(camelCaseWord -> camelCaseWord.contains(word))
+ .collect(Collectors.toSet());
+ if (camelCaseWords.isEmpty()) {
+ return false;
+ }
+
+ String text = myElement.getText();
+ for (String camelCaseWord : camelCaseWords) {
+ ProgressManager.checkCanceled();
+ int[] indexes = new StringSearcher(camelCaseWord, false, true).findAllOccurrences(text);
+ for (int index : indexes) {
+ TextRange hitRange = new TextRange(index, index + camelCaseWord.length());
+ if (range.intersectsStrict(hitRange)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean hasProblem(String word, TextRange range) {
+ if (!myManager.hasProblem(word)) {
+ return false;
+ }
+
+ // Check if a user has added CamelCase word to the project / app dictionary
+ if (hasCamelCaseMatch(word, range)) {
+ return false;
+ }
+
+ // If the word isn't "code" or contains letters outside the English alphabet,
+ // then diacritic check should be skipped
+ if (!myCodeLike || NON_ENGLISH_LETTERS.matcher(word).matches()) {
+ return true;
+ }
+
+ Project project = myElement.getProject();
+ return SpellCheckerManager.getInstance(project).getSuggestions(word)
+ .stream()
+ .filter(suggestion -> RenameUtil.isValidName(project, myElement, suggestion))
+ .noneMatch(suggestion -> Diacritics.equalsIgnoringDiacritics(word, suggestion));
+ }
+ }
+
+ private static boolean hasSameNamedReferenceInFile(String word, PsiElement element, SpellcheckingStrategy strategy) {
+ if (!strategy.elementFitsScope(element, Set.of(SpellCheckingScope.Comments))) {
+ return false;
+ }
+
+ PsiFile file = element.getContainingFile();
+ Map references = CachedValuesManager.getProjectPsiDependentCache(file, (psi) -> new ConcurrentHashMap<>());
+ return references.computeIfAbsent(word, key -> hasSameNamedReferencesInFile(key, file));
+ }
+
+ private static boolean hasSameNamedReferencesInFile(String word, PsiFile file) {
+ int[] occurrences = new StringSearcher(word, true, true).findAllOccurrences(file.getText());
+ if (occurrences.length <= 1) {
+ return false;
+ }
+
+ for (int occurrence : occurrences) {
+ PsiReference reference = file.findReferenceAt(occurrence);
+ PsiElement resolvedReference = reference != null ? reference.resolve() : null;
+ if (reference != null && resolvedReference != null && reference.getElement() != resolvedReference) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isCopyrightComment(SpellcheckingStrategy strategy, PsiElement psi) {
+ return strategy.elementFitsScope(psi, Set.of(SpellCheckingScope.Comments))
+ && StringUtil.containsIgnoreCase(psi.getText(), "Copyright")
+ && isAtFileStart(psi);
+ }
+
+ private static boolean isAtFileStart(PsiElement psi) {
+ PsiFile file = psi.getContainingFile();
+ int textStart = psi.getTextRange().getStartOffset();
+ return file.getViewProvider().getContents().subSequence(0, textStart).chars().noneMatch(Character::isLetterOrDigit);
+ }
+
+ private static void registerProblem(@NotNull SpellingTypo typo, @NotNull ProblemsHolder holder) {
+ registerProblem(holder, typo.getElement(), typo.getRange(), false, typo.getWord());
+ }
+
+ private static void registerProblem(@NotNull ProblemsHolder holder,
+ @NotNull PsiElement element,
+ @NotNull TextRange range,
+ boolean useRename,
+ String word) {
+ if (holder.isOnTheFly()) {
+ addRegularDescriptor(element, range, holder, useRename, word);
+ }
+ else {
+ addBatchDescriptor(element, range, word, holder);
+ }
+ }
+}
diff --git a/plugins/grazie/src/test/kotlin/com/intellij/grazie/GrazieTestBase.kt b/plugins/grazie/src/test/kotlin/com/intellij/grazie/GrazieTestBase.kt
index 5d4e46eb6d44..363d7c916e54 100644
--- a/plugins/grazie/src/test/kotlin/com/intellij/grazie/GrazieTestBase.kt
+++ b/plugins/grazie/src/test/kotlin/com/intellij/grazie/GrazieTestBase.kt
@@ -8,6 +8,7 @@ import com.intellij.grazie.ide.inspection.grammar.GrazieInspection
import com.intellij.grazie.jlanguage.Lang
import com.intellij.grazie.remote.HunspellDescriptor
import com.intellij.grazie.spellcheck.GrazieCheckers
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection
import com.intellij.grazie.style.StyleInspection
import com.intellij.grazie.text.TextChecker
import com.intellij.grazie.text.TextContent
@@ -25,7 +26,6 @@ import com.intellij.openapi.util.registry.Registry
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiPlainText
import com.intellij.spellchecker.SpellCheckerManager.Companion.getInstance
-import com.intellij.spellchecker.inspections.SpellCheckingInspection
import com.intellij.testFramework.ExtensionTestUtil
import com.intellij.testFramework.PlatformTestUtil
import com.intellij.testFramework.fixtures.BasePlatformTestCase
@@ -37,7 +37,7 @@ import kotlin.io.path.Path
abstract class GrazieTestBase : BasePlatformTestCase() {
companion object {
val inspectionTools by lazy {
- arrayOf(GrazieInspection(), SpellCheckingInspection(), StyleInspection())
+ arrayOf(GrazieInspection(), GrazieSpellCheckingInspection(), StyleInspection())
}
/**
diff --git a/plugins/grazie/src/test/kotlin/com/intellij/grazie/spellchecker/inspection/SpellcheckerInspectionTestCase.java b/plugins/grazie/src/test/kotlin/com/intellij/grazie/spellchecker/inspection/SpellcheckerInspectionTestCase.java
index 021de415e758..41eeb1aa1231 100644
--- a/plugins/grazie/src/test/kotlin/com/intellij/grazie/spellchecker/inspection/SpellcheckerInspectionTestCase.java
+++ b/plugins/grazie/src/test/kotlin/com/intellij/grazie/spellchecker/inspection/SpellcheckerInspectionTestCase.java
@@ -2,7 +2,7 @@
package com.intellij.grazie.spellchecker.inspection;
import com.intellij.codeInspection.LocalInspectionTool;
-import com.intellij.spellchecker.inspections.SpellCheckingInspection;
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection;
import com.intellij.testFramework.fixtures.BasePlatformTestCase;
public abstract class SpellcheckerInspectionTestCase extends BasePlatformTestCase {
@@ -22,6 +22,6 @@ public abstract class SpellcheckerInspectionTestCase extends BasePlatformTestCas
}
public static LocalInspectionTool[] getInspectionTools() {
- return new LocalInspectionTool[]{new SpellCheckingInspection()};
+ return new LocalInspectionTool[]{new GrazieSpellCheckingInspection()};
}
}
diff --git a/plugins/grazie/src/test/kotlin/com/intellij/grazie/spellchecker/inspection/quickfixes/AbstractSpellCheckerFixesTest.java b/plugins/grazie/src/test/kotlin/com/intellij/grazie/spellchecker/inspection/quickfixes/AbstractSpellCheckerFixesTest.java
index 0c47461fe1e2..a19e2b24aa2d 100644
--- a/plugins/grazie/src/test/kotlin/com/intellij/grazie/spellchecker/inspection/quickfixes/AbstractSpellCheckerFixesTest.java
+++ b/plugins/grazie/src/test/kotlin/com/intellij/grazie/spellchecker/inspection/quickfixes/AbstractSpellCheckerFixesTest.java
@@ -16,8 +16,8 @@
package com.intellij.grazie.spellchecker.inspection.quickfixes;
import com.intellij.codeInsight.intention.IntentionAction;
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection;
import com.intellij.grazie.spellchecker.inspection.SpellcheckerInspectionTestCase;
-import com.intellij.spellchecker.inspections.SpellCheckingInspection;
import com.intellij.spellchecker.quickfixes.ChangeTo;
import com.intellij.util.containers.ContainerUtil;
@@ -33,7 +33,7 @@ public abstract class AbstractSpellCheckerFixesTest extends SpellcheckerInspecti
private void doChangeToTest(int toSelect) {
myFixture.configureByFile(getBeforeFile());
- myFixture.enableInspections(SpellCheckingInspection.class);
+ myFixture.enableInspections(GrazieSpellCheckingInspection.class);
final IntentionAction intention = ContainerUtil.filter(
myFixture.getAvailableIntentions(), (it) -> it.getFamilyName().equals(ChangeTo.getFixName())
).get(toSelect + 1);
@@ -44,7 +44,7 @@ public abstract class AbstractSpellCheckerFixesTest extends SpellcheckerInspecti
protected void doNoQuickFixTest(String quickfix) {
myFixture.configureByFile(getBeforeFile());
- myFixture.enableInspections(SpellCheckingInspection.class);
+ myFixture.enableInspections(GrazieSpellCheckingInspection.class);
assertNull(myFixture.getAvailableIntention(quickfix));
}
diff --git a/plugins/grazie/src/test/kotlin/com/intellij/grazie/spellchecker/ui/SpellCheckingEditorCustomizationTest.java b/plugins/grazie/src/test/kotlin/com/intellij/grazie/spellchecker/ui/SpellCheckingEditorCustomizationTest.java
index e7fb96595028..041187cbb9fb 100644
--- a/plugins/grazie/src/test/kotlin/com/intellij/grazie/spellchecker/ui/SpellCheckingEditorCustomizationTest.java
+++ b/plugins/grazie/src/test/kotlin/com/intellij/grazie/spellchecker/ui/SpellCheckingEditorCustomizationTest.java
@@ -16,13 +16,13 @@
package com.intellij.grazie.spellchecker.ui;
import com.intellij.codeInspection.ex.InspectionProfileImpl;
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.SpellCheckingEditorCustomizationProvider;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileTypes.PlainTextFileType;
import com.intellij.openapi.fileTypes.PlainTextLanguage;
-import com.intellij.spellchecker.inspections.SpellCheckingInspection;
import com.intellij.testFramework.fixtures.BasePlatformTestCase;
import com.intellij.ui.EditorCustomization;
import com.intellij.ui.EditorTextFieldProvider;
@@ -48,7 +48,7 @@ public class SpellCheckingEditorCustomizationTest extends BasePlatformTestCase {
InspectionProfileImpl.INIT_INSPECTIONS = true;
try {
myFixture.configureByText(PlainTextFileType.INSTANCE, document);
- myFixture.enableInspections(new SpellCheckingInspection());
+ myFixture.enableInspections(new GrazieSpellCheckingInspection());
EditorCustomization customization = SpellCheckingEditorCustomizationProvider.getInstance().getCustomization(enabled);
assertNotNull(customization);
@@ -62,7 +62,7 @@ public class SpellCheckingEditorCustomizationTest extends BasePlatformTestCase {
}
public void testHighlightingWorksInEditorTextFieldWithCustomization() {
- myFixture.enableInspections(new SpellCheckingInspection());
+ myFixture.enableInspections(new GrazieSpellCheckingInspection());
var customization = SpellCheckingEditorCustomizationProvider.getInstance().getEnabledCustomization();
assertNotNull(customization);
diff --git a/plugins/groovy/BUILD.bazel b/plugins/groovy/BUILD.bazel
index b0715a79228d..cde20dd99cf7 100644
--- a/plugins/groovy/BUILD.bazel
+++ b/plugins/groovy/BUILD.bazel
@@ -146,6 +146,7 @@ jvm_library(
"//jps/jps-builders:build",
"//spellchecker",
"//spellchecker:spellchecker_test_lib",
+ "//plugins/grazie/src:core",
"//plugins/junit",
"//plugins/junit_rt:junit-rt",
"//java/java-indexing-api:indexing",
diff --git a/plugins/groovy/intellij.groovy.iml b/plugins/groovy/intellij.groovy.iml
index 9b1ca2044e67..9bf571696208 100644
--- a/plugins/groovy/intellij.groovy.iml
+++ b/plugins/groovy/intellij.groovy.iml
@@ -53,6 +53,7 @@
+
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovySpellcheckerTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovySpellcheckerTest.java
index 00ef3f55328c..9deceae87086 100644
--- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovySpellcheckerTest.java
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovySpellcheckerTest.java
@@ -1,7 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.plugins.groovy.lang;
-import com.intellij.spellchecker.inspections.SpellCheckingInspection;
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
public class GroovySpellcheckerTest extends LightJavaCodeInsightFixtureTestCase {
@@ -14,7 +14,7 @@ public class GroovySpellcheckerTest extends LightJavaCodeInsightFixtureTestCase
}
private void checkTypos() {
- myFixture.enableInspections(new SpellCheckingInspection());
+ myFixture.enableInspections(new GrazieSpellCheckingInspection());
myFixture.checkHighlighting(false, false, true);
}
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrSuppressionTest.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrSuppressionTest.java
index a644b2f94c57..23ef0383f26a 100644
--- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrSuppressionTest.java
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GrSuppressionTest.java
@@ -2,8 +2,7 @@
package org.jetbrains.plugins.groovy.lang.highlighting;
import com.intellij.analysis.AnalysisBundle;
-import com.intellij.codeInsight.intention.IntentionAction;
-import com.intellij.spellchecker.inspections.SpellCheckingInspection;
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection;
import com.intellij.testFramework.fixtures.JavaCodeInsightTestFixture;
import org.jetbrains.plugins.groovy.util.GroovyLatestTest;
import org.jetbrains.plugins.groovy.util.HighlightingTest;
@@ -12,7 +11,7 @@ import org.junit.Test;
public class GrSuppressionTest extends GroovyLatestTest implements HighlightingTest {
private void doTest(String before, String after) {
JavaCodeInsightTestFixture fixture = getFixture();
- fixture.enableInspections(SpellCheckingInspection.class);
+ fixture.enableInspections(GrazieSpellCheckingInspection.class);
configureByText(before);
fixture.checkHighlighting();
fixture.launchAction(fixture.getAvailableIntention(AnalysisBundle.message("suppress.inspection.file")));
diff --git a/plugins/htmltools/BUILD.bazel b/plugins/htmltools/BUILD.bazel
index a6f0cbb87e3b..fa177d9286a9 100644
--- a/plugins/htmltools/BUILD.bazel
+++ b/plugins/htmltools/BUILD.bazel
@@ -56,6 +56,7 @@ jvm_library(
"//platform/testFramework:testFramework_test_lib",
"//spellchecker",
"//spellchecker:spellchecker_test_lib",
+ "//plugins/grazie/src:core",
"//xml/xml-psi-api:psi",
"//xml/tests:tests_test_lib",
"//platform/core-ui",
diff --git a/plugins/htmltools/intellij.html.tools.tests.iml b/plugins/htmltools/intellij.html.tools.tests.iml
index cf6ce47a4000..3612ffb77f90 100644
--- a/plugins/htmltools/intellij.html.tools.tests.iml
+++ b/plugins/htmltools/intellij.html.tools.tests.iml
@@ -16,6 +16,7 @@
+
diff --git a/plugins/htmltools/testSrc/com/intellij/htmltools/codeInsight/daemon/HtmlHighlightingTest.java b/plugins/htmltools/testSrc/com/intellij/htmltools/codeInsight/daemon/HtmlHighlightingTest.java
index 1844b1c2de68..9a2db575442d 100644
--- a/plugins/htmltools/testSrc/com/intellij/htmltools/codeInsight/daemon/HtmlHighlightingTest.java
+++ b/plugins/htmltools/testSrc/com/intellij/htmltools/codeInsight/daemon/HtmlHighlightingTest.java
@@ -12,6 +12,7 @@ import com.intellij.codeInsight.intention.impl.CachedIntentions;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.ex.InspectionProfileImpl;
import com.intellij.codeInspection.htmlInspections.*;
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection;
import com.intellij.htmltools.HtmlToolsTestsUtil;
import com.intellij.htmltools.codeInspection.htmlInspections.HtmlDeprecatedAttributeInspection;
import com.intellij.htmltools.codeInspection.htmlInspections.HtmlDeprecatedTagInspection;
@@ -31,7 +32,6 @@ import com.intellij.openapi.editor.highlighter.HighlighterIterator;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlTokenType;
-import com.intellij.spellchecker.inspections.SpellCheckingInspection;
import com.intellij.testFramework.HighlightTestInfo;
import com.intellij.testFramework.fixtures.BasePlatformTestCase;
import com.intellij.xml.Html5SchemaProvider;
@@ -841,7 +841,7 @@ public class HtmlHighlightingTest extends BasePlatformTestCase {
}
public void testSpelling() {
- myFixture.enableInspections(new SpellCheckingInspection());
+ myFixture.enableInspections(new GrazieSpellCheckingInspection());
doTest();
}
diff --git a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/checkers/AbstractKotlinHighlightVisitorTest.java b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/checkers/AbstractKotlinHighlightVisitorTest.java
index 5e2d7ad4b7f2..d3aa82779a39 100644
--- a/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/checkers/AbstractKotlinHighlightVisitorTest.java
+++ b/plugins/kotlin/idea/tests/test/org/jetbrains/kotlin/checkers/AbstractKotlinHighlightVisitorTest.java
@@ -3,12 +3,12 @@
package org.jetbrains.kotlin.checkers;
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerEx;
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.platform.testFramework.core.FileComparisonFailedError;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
-import com.intellij.spellchecker.inspections.SpellCheckingInspection;
import com.intellij.testFramework.ExpectedHighlightingData;
import com.intellij.testFramework.fixtures.impl.JavaCodeInsightTestFixtureImpl;
import kotlin.Unit;
@@ -60,7 +60,7 @@ public abstract class AbstractKotlinHighlightVisitorTest extends KotlinLightCode
void doTestWithInfos(@NotNull String __) {
myFixture.configureByFile(fileName());
- myFixture.enableInspections(SpellCheckingInspection.class);
+ myFixture.enableInspections(GrazieSpellCheckingInspection.class);
try {
// TODO fix duplicate highlighting of some symbols
diff --git a/plugins/kotlin/idea/tests/testData/inspections/spelling/inspectionData/inspections.test b/plugins/kotlin/idea/tests/testData/inspections/spelling/inspectionData/inspections.test
index 7b9a63d95f8a..5c8ac1c822f2 100644
--- a/plugins/kotlin/idea/tests/testData/inspections/spelling/inspectionData/inspections.test
+++ b/plugins/kotlin/idea/tests/testData/inspections/spelling/inspectionData/inspections.test
@@ -1 +1 @@
-// INSPECTION_CLASS: com.intellij.spellchecker.inspections.SpellCheckingInspection
+// INSPECTION_CLASS: com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection
diff --git a/plugins/kotlin/idea/tests/testData/quickfix/suppress/external/suppressActive.kt b/plugins/kotlin/idea/tests/testData/quickfix/suppress/external/suppressActive.kt
index b7d45875a7c1..bf21292110d9 100644
--- a/plugins/kotlin/idea/tests/testData/quickfix/suppress/external/suppressActive.kt
+++ b/plugins/kotlin/idea/tests/testData/quickfix/suppress/external/suppressActive.kt
@@ -1,5 +1,5 @@
// "Typo: Change to..." "false"
-// TOOL: com.intellij.spellchecker.inspections.SpellCheckingInspection
+// TOOL: com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection
// ACTION: Convert property initializer to getter
// ACTION: Convert to 'buildString' call
// ACTION: Convert to lazy property
diff --git a/plugins/kotlin/idea/tests/testData/quickfix/suppress/external/suppressAvailable.kt b/plugins/kotlin/idea/tests/testData/quickfix/suppress/external/suppressAvailable.kt
index 0ad86079b1bf..448fb635d91f 100644
--- a/plugins/kotlin/idea/tests/testData/quickfix/suppress/external/suppressAvailable.kt
+++ b/plugins/kotlin/idea/tests/testData/quickfix/suppress/external/suppressAvailable.kt
@@ -1,5 +1,5 @@
// "Suppress 'SpellCheckingInspection' for val str" "true"
-// TOOL: com.intellij.spellchecker.inspections.SpellCheckingInspection
+// TOOL: com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection
val str = "kjsghkjshtiurhuig"
// FUS_K2_QUICKFIX_NAME: com.intellij.codeInspection.SuppressIntentionActionFromFix
diff --git a/plugins/kotlin/idea/tests/testData/quickfix/suppress/external/suppressAvailable.kt.after b/plugins/kotlin/idea/tests/testData/quickfix/suppress/external/suppressAvailable.kt.after
index af5f536c5f02..7b60259e935b 100644
--- a/plugins/kotlin/idea/tests/testData/quickfix/suppress/external/suppressAvailable.kt.after
+++ b/plugins/kotlin/idea/tests/testData/quickfix/suppress/external/suppressAvailable.kt.after
@@ -1,5 +1,5 @@
// "Suppress 'SpellCheckingInspection' for val str" "true"
-// TOOL: com.intellij.spellchecker.inspections.SpellCheckingInspection
+// TOOL: com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection
@Suppress("SpellCheckingInspection")
val str = "kjsghkjshtiurhuig"
diff --git a/plugins/markdown/test/BUILD.bazel b/plugins/markdown/test/BUILD.bazel
index 45b791454d8d..3c61e87faa0c 100644
--- a/plugins/markdown/test/BUILD.bazel
+++ b/plugins/markdown/test/BUILD.bazel
@@ -38,6 +38,7 @@ jvm_library(
"//platform/usageView",
"//spellchecker",
"//spellchecker:spellchecker_test_lib",
+ "//plugins/grazie/src:core",
"//xml/xml-psi-api:psi",
"//plugins/yaml",
"//plugins/yaml:yaml_test_lib",
diff --git a/plugins/markdown/test/intellij.markdown.tests.iml b/plugins/markdown/test/intellij.markdown.tests.iml
index 298ad632f78d..2bda490d4374 100644
--- a/plugins/markdown/test/intellij.markdown.tests.iml
+++ b/plugins/markdown/test/intellij.markdown.tests.iml
@@ -26,6 +26,7 @@
+
diff --git a/plugins/markdown/test/src/org/intellij/plugins/markdown/spellchecking/MarkdownSpellcheckerTest.java b/plugins/markdown/test/src/org/intellij/plugins/markdown/spellchecking/MarkdownSpellcheckerTest.java
index 45e4ffeb2f05..d9a709316c7b 100644
--- a/plugins/markdown/test/src/org/intellij/plugins/markdown/spellchecking/MarkdownSpellcheckerTest.java
+++ b/plugins/markdown/test/src/org/intellij/plugins/markdown/spellchecking/MarkdownSpellcheckerTest.java
@@ -2,7 +2,7 @@ package org.intellij.plugins.markdown.spellchecking;
import com.intellij.codeInsight.intention.IntentionManager;
import com.intellij.codeInsight.intention.impl.config.IntentionManagerImpl;
-import com.intellij.spellchecker.inspections.SpellCheckingInspection;
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection;
import com.intellij.testFramework.fixtures.BasePlatformTestCase;
import org.intellij.plugins.markdown.MarkdownTestingUtil;
@@ -11,7 +11,7 @@ public class MarkdownSpellcheckerTest extends BasePlatformTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
- myFixture.enableInspections(new SpellCheckingInspection());
+ myFixture.enableInspections(new GrazieSpellCheckingInspection());
}
public void testAll() {
diff --git a/plugins/maven/src/test/BUILD.bazel b/plugins/maven/src/test/BUILD.bazel
index 8803021914b6..b56d7e2a241f 100644
--- a/plugins/maven/src/test/BUILD.bazel
+++ b/plugins/maven/src/test/BUILD.bazel
@@ -45,6 +45,7 @@ jvm_library(
"//plugins/properties/properties-psi-api:psi",
"//spellchecker",
"//spellchecker:spellchecker_test_lib",
+ "//plugins/grazie/src:core",
"//platform/vcs-api:vcs",
"//plugins/groovy",
"//plugins/groovy:groovy_test_lib",
diff --git a/plugins/maven/src/test/intellij.maven.tests.iml b/plugins/maven/src/test/intellij.maven.tests.iml
index 05cb19d01e64..c15720177b84 100644
--- a/plugins/maven/src/test/intellij.maven.tests.iml
+++ b/plugins/maven/src/test/intellij.maven.tests.iml
@@ -31,6 +31,7 @@
+
diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/dom/MavenSpellcheckerTest.kt b/plugins/maven/src/test/java/org/jetbrains/idea/maven/dom/MavenSpellcheckerTest.kt
index ad2ddab2396d..ffd90caaf84e 100644
--- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/dom/MavenSpellcheckerTest.kt
+++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/dom/MavenSpellcheckerTest.kt
@@ -15,15 +15,15 @@
*/
package org.jetbrains.idea.maven.dom
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection
import com.intellij.maven.testFramework.MavenDomTestCase
-import com.intellij.spellchecker.inspections.SpellCheckingInspection
import kotlinx.coroutines.runBlocking
import org.junit.Test
class MavenSpellcheckerTest : MavenDomTestCase() {
@Test
fun testSpell() = runBlocking {
- fixture.enableInspections(SpellCheckingInspection::class.java)
+ fixture.enableInspections(GrazieSpellCheckingInspection::class.java)
createProjectPom("""
test
diff --git a/plugins/properties/tests/BUILD.bazel b/plugins/properties/tests/BUILD.bazel
index 37d796a07d33..bca2163b8135 100644
--- a/plugins/properties/tests/BUILD.bazel
+++ b/plugins/properties/tests/BUILD.bazel
@@ -34,6 +34,7 @@ jvm_library(
"//platform/util/diff",
"//spellchecker",
"//spellchecker:spellchecker_test_lib",
+ "//plugins/grazie/src:core",
"//java/openapi:java",
"//xml/impl",
"//plugins/properties:properties-backend",
diff --git a/plugins/properties/tests/intellij.properties.tests.iml b/plugins/properties/tests/intellij.properties.tests.iml
index 76de6b2bf756..41f91f203bc4 100644
--- a/plugins/properties/tests/intellij.properties.tests.iml
+++ b/plugins/properties/tests/intellij.properties.tests.iml
@@ -25,6 +25,7 @@
+
diff --git a/plugins/properties/tests/testSrc/com/intellij/lang/properties/PropertiesSpellcheckingTest.java b/plugins/properties/tests/testSrc/com/intellij/lang/properties/PropertiesSpellcheckingTest.java
index 8e73637bc95c..835d8915c378 100644
--- a/plugins/properties/tests/testSrc/com/intellij/lang/properties/PropertiesSpellcheckingTest.java
+++ b/plugins/properties/tests/testSrc/com/intellij/lang/properties/PropertiesSpellcheckingTest.java
@@ -15,13 +15,13 @@
*/
package com.intellij.lang.properties;
-import com.intellij.spellchecker.inspections.SpellCheckingInspection;
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection;
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
public class PropertiesSpellcheckingTest extends LightJavaCodeInsightFixtureTestCase {
public void testPropertiesSpellcheckingStrategy() {
- myFixture.enableInspections(new SpellCheckingInspection());
+ myFixture.enableInspections(new GrazieSpellCheckingInspection());
myFixture.configureByText("test.properties",
"""
diff --git a/plugins/properties/tests/testSrc/com/intellij/lang/properties/rename/PropertyRenameToTest.kt b/plugins/properties/tests/testSrc/com/intellij/lang/properties/rename/PropertyRenameToTest.kt
index 262c6fa94d39..a75201ecebfc 100644
--- a/plugins/properties/tests/testSrc/com/intellij/lang/properties/rename/PropertyRenameToTest.kt
+++ b/plugins/properties/tests/testSrc/com/intellij/lang/properties/rename/PropertyRenameToTest.kt
@@ -1,7 +1,7 @@
package com.intellij.lang.properties.rename
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection
import com.intellij.lang.properties.psi.impl.PropertyKeyImpl
-import com.intellij.spellchecker.inspections.SpellCheckingInspection
import com.intellij.testFramework.fixtures.BasePlatformTestCase
import com.intellij.util.ProcessingContext
@@ -21,7 +21,7 @@ class PropertyRenameToTest : BasePlatformTestCase() {
fun `test rename action is enabled and visible`() {
myFixture.configureByText("a.properties", "helloworld=value")
- myFixture.enableInspections(SpellCheckingInspection())
+ myFixture.enableInspections(GrazieSpellCheckingInspection())
myFixture.checkHighlighting()
myFixture.getAvailableIntention("Typo: Rename to…") ?: error("RenameTo intention is not available")
}
diff --git a/plugins/sh/core/BUILD.bazel b/plugins/sh/core/BUILD.bazel
index 08c6d91ace31..0f5b1c72f300 100644
--- a/plugins/sh/core/BUILD.bazel
+++ b/plugins/sh/core/BUILD.bazel
@@ -55,6 +55,7 @@ jvm_library(
"//plugins/sh/plugin:plugin-main",
"//spellchecker",
"//spellchecker:spellchecker_test_lib",
+ "//plugins/grazie/src:core",
"//platform/testFramework",
"//platform/testFramework:testFramework_test_lib",
"//platform/analysis-impl",
diff --git a/plugins/sh/core/intellij.sh.tests.iml b/plugins/sh/core/intellij.sh.tests.iml
index 68bf13386721..73496f49bc6f 100644
--- a/plugins/sh/core/intellij.sh.tests.iml
+++ b/plugins/sh/core/intellij.sh.tests.iml
@@ -16,6 +16,7 @@
+
diff --git a/plugins/sh/core/tests/com/intellij/sh/spellchecker/ShSpellcheckerTest.java b/plugins/sh/core/tests/com/intellij/sh/spellchecker/ShSpellcheckerTest.java
index 72642bc631a1..192f3070f762 100644
--- a/plugins/sh/core/tests/com/intellij/sh/spellchecker/ShSpellcheckerTest.java
+++ b/plugins/sh/core/tests/com/intellij/sh/spellchecker/ShSpellcheckerTest.java
@@ -1,8 +1,8 @@
// Copyright 2000-2019 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.sh.spellchecker;
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection;
import com.intellij.openapi.application.PluginPathManager;
-import com.intellij.spellchecker.inspections.SpellCheckingInspection;
import com.intellij.testFramework.fixtures.BasePlatformTestCase;
public class ShSpellcheckerTest extends BasePlatformTestCase {
@@ -14,7 +14,7 @@ public class ShSpellcheckerTest extends BasePlatformTestCase {
@Override
public void setUp() throws Exception {
super.setUp();
- myFixture.enableInspections(new SpellCheckingInspection());
+ myFixture.enableInspections(new GrazieSpellCheckingInspection());
}
public void testTypoInString() { doTest(); }
diff --git a/plugins/textmate/tests/BUILD.bazel b/plugins/textmate/tests/BUILD.bazel
index 8c7a575cf1fb..15d80b92ce6f 100644
--- a/plugins/textmate/tests/BUILD.bazel
+++ b/plugins/textmate/tests/BUILD.bazel
@@ -41,6 +41,7 @@ jvm_library(
"//platform/editor-ui-api:editor-ui",
"//spellchecker",
"//spellchecker:spellchecker_test_lib",
+ "//plugins/grazie/src:core",
"//platform/projectModel-api:projectModel",
"//plugins/textmate/plugin",
"//plugins/textmate/backend",
diff --git a/plugins/textmate/tests/intellij.textmate.tests.iml b/plugins/textmate/tests/intellij.textmate.tests.iml
index 03e29db6ac21..2675aa0107d5 100644
--- a/plugins/textmate/tests/intellij.textmate.tests.iml
+++ b/plugins/textmate/tests/intellij.textmate.tests.iml
@@ -27,6 +27,7 @@
+
diff --git a/plugins/textmate/tests/tests/org/jetbrains/plugins/textmate/spellchecker/TextMateSpellcheckingTest.java b/plugins/textmate/tests/tests/org/jetbrains/plugins/textmate/spellchecker/TextMateSpellcheckingTest.java
index 9a47f15e81f6..64f8e1a5249e 100644
--- a/plugins/textmate/tests/tests/org/jetbrains/plugins/textmate/spellchecker/TextMateSpellcheckingTest.java
+++ b/plugins/textmate/tests/tests/org/jetbrains/plugins/textmate/spellchecker/TextMateSpellcheckingTest.java
@@ -1,11 +1,11 @@
package org.jetbrains.plugins.textmate.spellchecker;
-import com.intellij.spellchecker.inspections.SpellCheckingInspection;
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection;
import org.jetbrains.plugins.textmate.TextMateAcceptanceTestCase;
public class TextMateSpellcheckingTest extends TextMateAcceptanceTestCase {
public void testSimple() {
- myFixture.enableInspections(SpellCheckingInspection.class);
+ myFixture.enableInspections(GrazieSpellCheckingInspection.class);
myFixture.configureByText("test.md_hack", "some typooo");
myFixture.checkHighlighting();
}
diff --git a/plugins/yaml/backend/BUILD.bazel b/plugins/yaml/backend/BUILD.bazel
index 06cdd3a89f63..5385a4de5642 100644
--- a/plugins/yaml/backend/BUILD.bazel
+++ b/plugins/yaml/backend/BUILD.bazel
@@ -73,6 +73,7 @@ jvm_library(
"//platform/testFramework:testFramework_test_lib",
"//spellchecker",
"//spellchecker:spellchecker_test_lib",
+ "//plugins/grazie/src:core",
"//platform/platform-impl:ide-impl",
"//json/backend",
"//json/backend/tests:tests_test_lib",
diff --git a/plugins/yaml/backend/intellij.yaml.backend.iml b/plugins/yaml/backend/intellij.yaml.backend.iml
index aa121b363404..78f84ef98731 100644
--- a/plugins/yaml/backend/intellij.yaml.backend.iml
+++ b/plugins/yaml/backend/intellij.yaml.backend.iml
@@ -24,6 +24,7 @@
+
diff --git a/plugins/yaml/backend/testSrc/highlighting/YAMLSpellCheckerTest.kt b/plugins/yaml/backend/testSrc/highlighting/YAMLSpellCheckerTest.kt
index 9bda78a809ca..005dca29fbe8 100644
--- a/plugins/yaml/backend/testSrc/highlighting/YAMLSpellCheckerTest.kt
+++ b/plugins/yaml/backend/testSrc/highlighting/YAMLSpellCheckerTest.kt
@@ -1,7 +1,7 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.yaml.highlighting
-import com.intellij.spellchecker.inspections.SpellCheckingInspection
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection
import com.intellij.testFramework.fixtures.BasePlatformTestCase
import com.intellij.testFramework.fixtures.InjectionTestFixture
import org.intellij.lang.regexp.RegExpLanguage
@@ -10,7 +10,7 @@ class YAMLSpellCheckerTest : BasePlatformTestCase() {
override fun setUp() {
super.setUp()
- myFixture.enableInspections(SpellCheckingInspection::class.java)
+ myFixture.enableInspections(GrazieSpellCheckingInspection::class.java)
}
fun testSpellChecking() {
diff --git a/plugins/yaml/backend/testSrc/schema/YamlWithSchemaSpellcheckingTest.kt b/plugins/yaml/backend/testSrc/schema/YamlWithSchemaSpellcheckingTest.kt
index df3fbe2f2a4b..d87f2800c050 100644
--- a/plugins/yaml/backend/testSrc/schema/YamlWithSchemaSpellcheckingTest.kt
+++ b/plugins/yaml/backend/testSrc/schema/YamlWithSchemaSpellcheckingTest.kt
@@ -2,10 +2,10 @@
package org.jetbrains.yaml.schema
import com.intellij.codeInspection.InspectionProfileEntry
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection
import com.intellij.openapi.application.ex.PathManagerEx
import com.intellij.openapi.fileTypes.LanguageFileType
import com.intellij.openapi.vfs.VirtualFile
-import com.intellij.spellchecker.inspections.SpellCheckingInspection
import com.jetbrains.jsonSchema.JsonSchemaHighlightingTestBase
import org.jetbrains.yaml.YAMLLanguage
import java.util.function.Predicate
@@ -31,7 +31,7 @@ class YamlWithSchemaSpellcheckingTest : JsonSchemaHighlightingTestBase() {
}
fun testYamlSpellcheckingWithSchema() {
- myFixture.enableInspections(SpellCheckingInspection::class.java)
+ myFixture.enableInspections(GrazieSpellCheckingInspection::class.java)
val schema = """
{
"properties": {
diff --git a/python/testSrc/com/jetbrains/python/PySpellCheckerTest.java b/python/testSrc/com/jetbrains/python/PySpellCheckerTest.java
index c4c844d69b67..ad59d38695b0 100644
--- a/python/testSrc/com/jetbrains/python/PySpellCheckerTest.java
+++ b/python/testSrc/com/jetbrains/python/PySpellCheckerTest.java
@@ -1,7 +1,7 @@
// Copyright 2000-2021 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.jetbrains.python;
-import com.intellij.spellchecker.inspections.SpellCheckingInspection;
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.psi.LanguageLevel;
@@ -70,7 +70,7 @@ public class PySpellCheckerTest extends PyTestCase {
}
private void doTest() {
- myFixture.enableInspections(SpellCheckingInspection.class);
+ myFixture.enableInspections(GrazieSpellCheckingInspection.class);
myFixture.configureByFile("inspections/spelling/" + getTestName(true) + ".py");
myFixture.checkHighlighting(true, false, true);
}
diff --git a/python/testSrc/com/jetbrains/python/inspections/flake8/Flake8InspectionSuppressorTest.java b/python/testSrc/com/jetbrains/python/inspections/flake8/Flake8InspectionSuppressorTest.java
index cfed0d835a72..d67012de2b1c 100644
--- a/python/testSrc/com/jetbrains/python/inspections/flake8/Flake8InspectionSuppressorTest.java
+++ b/python/testSrc/com/jetbrains/python/inspections/flake8/Flake8InspectionSuppressorTest.java
@@ -2,8 +2,8 @@
package com.jetbrains.python.inspections.flake8;
import com.intellij.codeInspection.LocalInspectionTool;
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection;
import com.intellij.psi.PsiFile;
-import com.intellij.spellchecker.inspections.SpellCheckingInspection;
import com.jetbrains.python.PythonFileType;
import com.jetbrains.python.fixtures.PyTestCase;
import com.jetbrains.python.inspections.PyComparisonWithNoneInspection;
@@ -39,7 +39,7 @@ public class Flake8InspectionSuppressorTest extends PyTestCase {
public void testSuppressingNonPythonSpecificInspections() {
doTestByText("s = 'ipaddress' # noqa",
- SpellCheckingInspection.class);
+ GrazieSpellCheckingInspection.class);
}
public void testTopLevelCommentsIgnored() {
diff --git a/python/testSrc/com/jetbrains/python/inspections/typeignore/TypeIgnoreInspectionSuppressorTest.kt b/python/testSrc/com/jetbrains/python/inspections/typeignore/TypeIgnoreInspectionSuppressorTest.kt
index f0963353a317..07de41789061 100644
--- a/python/testSrc/com/jetbrains/python/inspections/typeignore/TypeIgnoreInspectionSuppressorTest.kt
+++ b/python/testSrc/com/jetbrains/python/inspections/typeignore/TypeIgnoreInspectionSuppressorTest.kt
@@ -1,8 +1,8 @@
// Copyright 2000-2021 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.jetbrains.python.inspections.typeignore
+import com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection
import com.intellij.psi.PsiFile
-import com.intellij.spellchecker.inspections.SpellCheckingInspection
import com.jetbrains.python.PythonFileType
import com.jetbrains.python.fixtures.PyTestCase
import com.jetbrains.python.inspections.*
@@ -53,7 +53,7 @@ class TypeIgnoreInspectionSuppressorTest : PyTestCase() {
}
fun testWithNoqa() {
- myFixture.enableInspections(SpellCheckingInspection::class.java)
+ myFixture.enableInspections(GrazieSpellCheckingInspection::class.java)
doTestByText("""
def foo(x: str):
print(x.bar + 'ajsd') # type: ignore # noqa
diff --git a/spellchecker/resources/intellij.spellchecker.xml b/spellchecker/resources/intellij.spellchecker.xml
index 998e2ddcd4fb..ec57114422ec 100644
--- a/spellchecker/resources/intellij.spellchecker.xml
+++ b/spellchecker/resources/intellij.spellchecker.xml
@@ -28,11 +28,6 @@
-
-
diff --git a/spellchecker/src/com/intellij/spellchecker/inspections/SpellCheckingInspection.java b/spellchecker/src/com/intellij/spellchecker/inspections/SpellCheckingInspection.java
index ffb44994ccbd..4244ec9ddea9 100644
--- a/spellchecker/src/com/intellij/spellchecker/inspections/SpellCheckingInspection.java
+++ b/spellchecker/src/com/intellij/spellchecker/inspections/SpellCheckingInspection.java
@@ -2,145 +2,25 @@
package com.intellij.spellchecker.inspections;
import com.intellij.codeInspection.*;
-import com.intellij.codeInspection.options.OptPane;
-import com.intellij.lang.LanguageNamesValidation;
-import com.intellij.lang.injection.InjectedLanguageManager;
-import com.intellij.lang.refactoring.NamesValidator;
-import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DumbAware;
-import com.intellij.openapi.project.DumbService;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.TextRange;
-import com.intellij.openapi.util.registry.Registry;
-import com.intellij.openapi.util.text.StringUtil;
-import com.intellij.profile.codeInspection.InspectionProfileManager;
-import com.intellij.psi.*;
-import com.intellij.psi.util.CachedValuesManager;
-import com.intellij.refactoring.rename.RenameUtil;
-import com.intellij.spellchecker.SpellCheckerManager;
-import com.intellij.spellchecker.grazie.diacritic.Diacritics;
-import com.intellij.spellchecker.inspections.SpellcheckingExtension.SpellCheckingResult;
-import com.intellij.spellchecker.inspections.SpellcheckingExtension.SpellingTypo;
-import com.intellij.spellchecker.tokenizer.LanguageSpellchecking;
+import com.intellij.psi.PsiElement;
import com.intellij.spellchecker.tokenizer.SpellcheckingStrategy;
-import com.intellij.spellchecker.tokenizer.SuppressibleSpellcheckingStrategy;
import com.intellij.spellchecker.tokenizer.TokenConsumer;
-import com.intellij.spellchecker.util.SpellCheckerBundle;
-import com.intellij.util.Consumer;
-import com.intellij.util.containers.CollectionFactory;
-import com.intellij.util.text.StringSearcher;
-import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import java.util.HashSet;
-import java.util.Map;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import static com.intellij.codeInspection.options.OptPane.checkbox;
-import static com.intellij.codeInspection.options.OptPane.pane;
+import static com.intellij.spellchecker.tokenizer.SpellcheckingStrategy.getSpellcheckingStrategy;
-public final class SpellCheckingInspection extends LocalInspectionTool implements DumbAware {
+/**
+ * Please use {@link com.intellij.grazie.spellcheck.GrazieSpellCheckingInspection} instead.
+ * The class is not marked as deprecated even though it is not used as an inspection anymore
+ * because {@link SpellCheckingScope} and both {@link SpellCheckingInspection#tokenize} methods are not deprecated and will not be in foreseeable future.
+ * They should be present here to preserve backward compatibility.
+ */
+public abstract class SpellCheckingInspection extends LocalInspectionTool implements DumbAware {
public static final String SPELL_CHECKING_INSPECTION_TOOL_NAME = "SpellCheckingInspection";
- @Override
- public SuppressQuickFix @NotNull [] getBatchSuppressActions(@Nullable PsiElement element) {
- if (element != null) {
- SpellcheckingStrategy strategy = getSpellcheckingStrategy(element);
- if (strategy instanceof SuppressibleSpellcheckingStrategy) {
- return ((SuppressibleSpellcheckingStrategy)strategy).getSuppressActions(element, getShortName());
- }
- }
- return super.getBatchSuppressActions(element);
- }
-
- public static SpellcheckingStrategy getSpellcheckingStrategy(@NotNull PsiElement element) {
- DumbService dumbService = DumbService.getInstance(element.getProject());
- for (SpellcheckingStrategy strategy : LanguageSpellchecking.INSTANCE.allForLanguage(element.getLanguage())) {
- if (dumbService.isUsableInCurrentContext(strategy) && strategy.isMyContext(element)) {
- return strategy;
- }
- }
- return null;
- }
-
- @Override
- public boolean isSuppressedFor(@NotNull PsiElement element) {
- SpellcheckingStrategy strategy = getSpellcheckingStrategy(element);
- if (strategy instanceof SuppressibleSpellcheckingStrategy) {
- return ((SuppressibleSpellcheckingStrategy)strategy).isSuppressedFor(element, getShortName());
- }
- return super.isSuppressedFor(element);
- }
-
- @Override
- public @NonNls @NotNull String getShortName() {
- return SPELL_CHECKING_INSPECTION_TOOL_NAME;
- }
-
- @Override
- public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
- return super.buildVisitor(holder, isOnTheFly);
- }
-
- @Override
- public @NotNull PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder,
- boolean isOnTheFly,
- @NotNull LocalInspectionToolSession session) {
- if (!Registry.is("spellchecker.inspection.enabled", true) ||
- InspectionProfileManager.hasTooLowSeverity(session, this) ||
- InjectedLanguageManager.getInstance(holder.getProject()).isFrankensteinInjection(holder.getFile())) {
- return PsiElementVisitor.EMPTY_VISITOR;
- }
-
- var scopes = buildAllowedScopes();
- SpellCheckerManager manager = SpellCheckerManager.getInstance(holder.getProject());
- return new PsiElementVisitor() {
- @Override
- public void visitWhiteSpace(@NotNull PsiWhiteSpace space) { }
-
- @Override
- public void visitElement(final @NotNull PsiElement element) {
- if (holder.getResultCount() > 1000 || element.getNode() == null) return;
-
- var strategy = getSpellcheckingStrategy(element);
- if (strategy == null || !strategy.elementFitsScope(element, scopes) || isCopyrightComment(strategy, element)) return;
-
- SpellCheckingResult result = SpellcheckingExtension.Companion.spellcheck(
- element, strategy, session,
- typo -> {
- if (hasSameNamedReferenceInFile(typo.getWord(), element, strategy)) return;
- registerProblem(typo, holder);
- }
- );
- if (result == SpellCheckingResult.Checked) return;
-
- tokenize(
- strategy, element,
- new MyTokenConsumer(manager, strategy, holder, LanguageNamesValidation.INSTANCE.forLanguage(element.getLanguage())),
- scopes
- );
- }
- };
- }
-
- private Set buildAllowedScopes() {
- var result = new HashSet();
- if (processLiterals) {
- result.add(SpellCheckingScope.Literals);
- }
- if (processComments) {
- result.add(SpellCheckingScope.Comments);
- }
- if (processCode) {
- result.add(SpellCheckingScope.Code);
- }
- return result;
- }
-
/**
* Splits element text in tokens according to spell checker strategy of given language
*
@@ -156,220 +36,15 @@ public final class SpellCheckingInspection extends LocalInspectionTool implement
tokenize(factoryByLanguage, element, consumer, allowedScopes);
}
- private static void tokenize(SpellcheckingStrategy strategy,
- PsiElement element,
- TokenConsumer consumer,
- Set allowedScopes) {
+ public static void tokenize(SpellcheckingStrategy strategy,
+ PsiElement element,
+ TokenConsumer consumer,
+ Set allowedScopes) {
var tokenizer = strategy.getTokenizer(element, allowedScopes);
//noinspection unchecked
tokenizer.tokenize(element, consumer);
}
- private static void addBatchDescriptor(@NotNull PsiElement element,
- @NotNull TextRange textRange,
- @NotNull String word,
- @NotNull ProblemsHolder holder) {
- var fixes = SpellcheckingStrategy.getDefaultBatchFixes(element, textRange, word);
- ProblemDescriptor problemDescriptor = createProblemDescriptor(element, textRange, fixes, false);
- holder.registerProblem(problemDescriptor);
- }
-
- private static void addRegularDescriptor(@NotNull PsiElement element, @NotNull TextRange textRange, @NotNull ProblemsHolder holder,
- boolean useRename, String wordWithTypo) {
- SpellcheckingStrategy strategy = getSpellcheckingStrategy(element);
-
- LocalQuickFix[] fixes = strategy != null
- ? strategy.getRegularFixes(element, textRange, useRename, wordWithTypo)
- : SpellcheckingStrategy.getDefaultRegularFixes(useRename, wordWithTypo, element, textRange);
-
- final ProblemDescriptor problemDescriptor = createProblemDescriptor(element, textRange, fixes, true);
- holder.registerProblem(problemDescriptor);
- }
-
- private static ProblemDescriptor createProblemDescriptor(PsiElement element, TextRange textRange,
- LocalQuickFix[] fixes,
- boolean onTheFly) {
- final String description = SpellCheckerBundle.message("typo.in.word.ref");
- return new ProblemDescriptorBase(element, element, description, fixes, ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
- false, textRange, onTheFly, onTheFly);
- }
-
- @SuppressWarnings("PublicField")
- public boolean processCode = true;
- public boolean processLiterals = true;
- public boolean processComments = true;
-
- @Override
- public @NotNull OptPane getOptionsPane() {
- return pane(
- checkbox("processCode", SpellCheckerBundle.message("process.code")),
- checkbox("processLiterals", SpellCheckerBundle.message("process.literals")),
- checkbox("processComments", SpellCheckerBundle.message("process.comments"))
- );
- }
-
- private static final class MyTokenConsumer extends TokenConsumer implements Consumer {
- private static final Pattern NON_ENGLISH_LETTERS = Pattern.compile(".*[^a-zA-Z].*");
-
- private final Set myAlreadyChecked = CollectionFactory.createSmallMemoryFootprintSet();
- private final SpellCheckerManager myManager;
- private final ProblemsHolder myHolder;
- private final NamesValidator myNamesValidator;
- private final SpellcheckingStrategy myStrategy;
- private boolean myCodeLike;
- private PsiElement myElement;
- private String myText;
- private boolean myUseRename;
- private int myOffset;
-
- MyTokenConsumer(SpellCheckerManager manager, SpellcheckingStrategy strategy, ProblemsHolder holder, NamesValidator namesValidator) {
- myManager = manager;
- myStrategy = strategy;
- myHolder = holder;
- myNamesValidator = namesValidator;
- }
-
- @Override
- public void consumeToken(final PsiElement element,
- final String text,
- final boolean useRename,
- final int offset,
- TextRange rangeToCheck,
- Splitter splitter) {
- myElement = element;
- myText = text;
- myUseRename = useRename;
- myOffset = offset;
- myCodeLike = myStrategy.elementFitsScope(myElement, Set.of(SpellCheckingScope.Code));
- splitter.split(text, rangeToCheck, this);
- }
-
- @Override
- public void consume(TextRange range) {
- // Tokenization of large texts can produce a lot of tokens, but we are inside RA
- ProgressManager.checkCanceled();
- String word = range.substring(myText);
- if (!myHolder.isOnTheFly() && myAlreadyChecked.contains(word)) {
- return;
- }
-
- boolean keyword = myNamesValidator.isKeyword(word, myElement.getProject());
- if (keyword || !hasProblem(word, range) || hasSameNamedReferenceInFile(word, myElement, myStrategy)) {
- return;
- }
-
- range = myStrategy.getTokenizer(myElement)
- .getHighlightingRange(myElement, myOffset, range);
- assert range.getStartOffset() >= 0;
-
- if (!myHolder.isOnTheFly()) {
- myAlreadyChecked.add(word);
- }
- registerProblem(myHolder, myElement, range, myUseRename, word);
- }
-
- private boolean hasCamelCaseMatch(String word, TextRange range) {
- Set camelCaseWords = myManager.getUserCamelCaseWords()
- .stream()
- .filter(camelCaseWord -> camelCaseWord.contains(word))
- .collect(Collectors.toSet());
- if (camelCaseWords.isEmpty()) {
- return false;
- }
-
- String text = myElement.getText();
- for (String camelCaseWord : camelCaseWords) {
- ProgressManager.checkCanceled();
- int[] indexes = new StringSearcher(camelCaseWord, false, true).findAllOccurrences(text);
- for (int index : indexes) {
- TextRange hitRange = new TextRange(index, index + camelCaseWord.length());
- if (range.intersectsStrict(hitRange)) {
- return true;
- }
- }
- }
- return false;
- }
-
- private boolean hasProblem(String word, TextRange range) {
- if (!myManager.hasProblem(word)) {
- return false;
- }
-
- // Check if a user has added CamelCase word to the project / app dictionary
- if (hasCamelCaseMatch(word, range)) {
- return false;
- }
-
- // If the word isn't "code" or contains letters outside the English alphabet,
- // then diacritic check should be skipped
- if (!myCodeLike || NON_ENGLISH_LETTERS.matcher(word).matches()) {
- return true;
- }
-
- Project project = myElement.getProject();
- return SpellCheckerManager.getInstance(project).getSuggestions(word)
- .stream()
- .filter(suggestion -> RenameUtil.isValidName(project, myElement, suggestion))
- .noneMatch(suggestion -> Diacritics.equalsIgnoringDiacritics(word, suggestion));
- }
- }
-
- private static boolean hasSameNamedReferenceInFile(String word, PsiElement element, SpellcheckingStrategy strategy) {
- if (!strategy.elementFitsScope(element, Set.of(SpellCheckingScope.Comments))) {
- return false;
- }
-
- PsiFile file = element.getContainingFile();
- Map references = CachedValuesManager.getProjectPsiDependentCache(file, (psi) -> new ConcurrentHashMap<>());
- return references.computeIfAbsent(word, key -> hasSameNamedReferencesInFile(key, file));
- }
-
- private static boolean hasSameNamedReferencesInFile(String word, PsiFile file) {
- int[] occurrences = new StringSearcher(word, true, true).findAllOccurrences(file.getText());
- if (occurrences.length <= 1) {
- return false;
- }
-
- for (int occurrence : occurrences) {
- PsiReference reference = file.findReferenceAt(occurrence);
- PsiElement resolvedReference = reference != null ? reference.resolve() : null;
- if (reference != null && resolvedReference != null && reference.getElement() != resolvedReference) {
- return true;
- }
- }
- return false;
- }
-
- private static boolean isCopyrightComment(SpellcheckingStrategy strategy, PsiElement psi) {
- return strategy.elementFitsScope(psi, Set.of(SpellCheckingScope.Comments))
- && StringUtil.containsIgnoreCase(psi.getText(), "Copyright")
- && isAtFileStart(psi);
- }
-
- private static boolean isAtFileStart(PsiElement psi) {
- PsiFile file = psi.getContainingFile();
- int textStart = psi.getTextRange().getStartOffset();
- return file.getViewProvider().getContents().subSequence(0, textStart).chars().noneMatch(Character::isLetterOrDigit);
- }
-
- private static void registerProblem(@NotNull SpellingTypo typo, @NotNull ProblemsHolder holder) {
- registerProblem(holder, typo.getElement(), typo.getRange(), false, typo.getWord());
- }
-
- private static void registerProblem(@NotNull ProblemsHolder holder,
- @NotNull PsiElement element,
- @NotNull TextRange range,
- boolean useRename,
- String word) {
- if (holder.isOnTheFly()) {
- addRegularDescriptor(element, range, holder, useRename, word);
- }
- else {
- addBatchDescriptor(element, range, word, holder);
- }
- }
-
public enum SpellCheckingScope {
Comments,
Literals,
diff --git a/spellchecker/src/com/intellij/spellchecker/statistics/SpellcheckerRateTracker.kt b/spellchecker/src/com/intellij/spellchecker/statistics/SpellcheckerRateTracker.kt
index ea5455d6ed30..9771c88d4ba2 100644
--- a/spellchecker/src/com/intellij/spellchecker/statistics/SpellcheckerRateTracker.kt
+++ b/spellchecker/src/com/intellij/spellchecker/statistics/SpellcheckerRateTracker.kt
@@ -5,8 +5,8 @@ import com.intellij.lang.Language
import com.intellij.openapi.project.Project
import com.intellij.openapi.vcs.ui.CommitMessage
import com.intellij.psi.PsiElement
-import com.intellij.spellchecker.inspections.SpellCheckingInspection
import com.intellij.spellchecker.inspections.SpellCheckingInspection.SpellCheckingScope
+import com.intellij.spellchecker.tokenizer.SpellcheckingStrategy.getSpellcheckingStrategy
import kotlin.concurrent.atomics.AtomicBoolean
import kotlin.concurrent.atomics.ExperimentalAtomicApi
@@ -30,7 +30,7 @@ class SpellcheckerRateTracker private constructor(
companion object {
private fun determineDomain(element: PsiElement): String {
- val strategy = SpellCheckingInspection.getSpellcheckingStrategy(element)
+ val strategy = getSpellcheckingStrategy(element)
if (CommitMessage.isCommitMessage(element)) {
return "commit"
}
diff --git a/spellchecker/src/com/intellij/spellchecker/tokenizer/SpellcheckingStrategy.java b/spellchecker/src/com/intellij/spellchecker/tokenizer/SpellcheckingStrategy.java
index 45f6d8700eed..d3c6b30ec1de 100644
--- a/spellchecker/src/com/intellij/spellchecker/tokenizer/SpellcheckingStrategy.java
+++ b/spellchecker/src/com/intellij/spellchecker/tokenizer/SpellcheckingStrategy.java
@@ -9,6 +9,7 @@ import com.intellij.lang.ParserDefinition;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.impl.CustomSyntaxTableFileType;
+import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.PossiblyDumbAware;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
@@ -150,6 +151,16 @@ public class SpellcheckingStrategy implements PossiblyDumbAware {
return getDefaultRegularFixes(useRename, typo, element, textRange);
}
+ public static SpellcheckingStrategy getSpellcheckingStrategy(@NotNull PsiElement element) {
+ DumbService dumbService = DumbService.getInstance(element.getProject());
+ for (SpellcheckingStrategy strategy : LanguageSpellchecking.INSTANCE.allForLanguage(element.getLanguage())) {
+ if (dumbService.isUsableInCurrentContext(strategy) && strategy.isMyContext(element)) {
+ return strategy;
+ }
+ }
+ return null;
+ }
+
public static LocalQuickFix[] getDefaultRegularFixes(boolean useRename,
String typo,
@NotNull PsiElement element,
diff --git a/spellchecker/src/com/intellij/spellchecker/ui/SpellCheckingEditorCustomization.java b/spellchecker/src/com/intellij/spellchecker/ui/SpellCheckingEditorCustomization.java
index 031535561f41..e9158751f0e6 100644
--- a/spellchecker/src/com/intellij/spellchecker/ui/SpellCheckingEditorCustomization.java
+++ b/spellchecker/src/com/intellij/spellchecker/ui/SpellCheckingEditorCustomization.java
@@ -5,10 +5,8 @@ import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.intention.IntentionManager;
import com.intellij.codeInspection.InspectionProfile;
-import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.ex.InspectionProfileImpl;
import com.intellij.codeInspection.ex.InspectionProfileWrapper;
-import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.project.Project;
@@ -21,9 +19,6 @@ import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.containers.CollectionFactory;
import org.jetbrains.annotations.NotNull;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
@@ -34,51 +29,14 @@ import java.util.function.Function;
* Thread-safe.
*/
public class SpellCheckingEditorCustomization extends SimpleEditorCustomization {
- private static volatile Map SPELL_CHECK_TOOLS;
- private static volatile boolean READY;
-
SpellCheckingEditorCustomization(boolean enabled) {
super(enabled);
}
- private static @NotNull Map getSpellCheckTools() {
- Map tools = SPELL_CHECK_TOOLS;
- if (tools == null) {
- tools = new HashMap<>();
- // It's assumed that default spell checking inspection settings are just fine for processing all types of data.
- // Please perform corresponding settings tuning if that assumption is broken in the future.
- Class[] inspectionClasses = (Class[])new Class>[]{SpellCheckingInspection.class};
- for (Class inspectionClass : inspectionClasses) {
- try {
- LocalInspectionTool tool = inspectionClass.newInstance();
- tools.put(tool.getShortName(), new LocalInspectionToolWrapper(tool));
- }
- catch (Throwable e) {
- READY = false;
- return Map.of();
- }
- }
- SPELL_CHECK_TOOLS = tools;
- READY = true;
- }
- return tools;
- }
-
- private static boolean isReady() {
- if (SPELL_CHECK_TOOLS == null) {
- getSpellCheckTools();
- }
- return READY;
- }
-
@Override
public void customize(@NotNull EditorEx editor) {
boolean apply = isEnabled();
- if (!isReady()) {
- return;
- }
-
Project project = editor.getProject();
if (project == null) {
return;
@@ -119,7 +77,7 @@ public class SpellCheckingEditorCustomization extends SimpleEditorCustomization
}
static Set getSpellCheckingToolNames() {
- return Collections.unmodifiableSet(getSpellCheckTools().keySet());
+ return Set.of(SpellCheckingInspection.SPELL_CHECKING_INSPECTION_TOOL_NAME);
}
private static class MyInspectionProfileStrategy implements Function {
@@ -129,9 +87,6 @@ public class SpellCheckingEditorCustomization extends SimpleEditorCustomization
@Override
public @NotNull InspectionProfileWrapper apply(@NotNull InspectionProfile profile) {
- if (!isReady()) {
- return new InspectionProfileWrapper((InspectionProfileImpl)profile);
- }
MyInspectionProfileWrapper wrapper = myWrappers.get(profile);
return wrapper == null
? ConcurrencyUtil.cacheOrGet(myWrappers, profile, new MyInspectionProfileWrapper(profile, myUseSpellCheck))
@@ -153,7 +108,7 @@ public class SpellCheckingEditorCustomization extends SimpleEditorCustomization
@Override
public boolean isToolEnabled(HighlightDisplayKey key, PsiElement element) {
- return (key != null && getSpellCheckTools().containsKey(key.getShortName()) ? myUseSpellCheck : super.isToolEnabled(key, element));
+ return (key != null && getSpellCheckingToolNames().contains(key.getShortName()) ? myUseSpellCheck : super.isToolEnabled(key, element));
}
}
}