Summary
XMLSpellcheckDelegate.shouldSpellcheck(int, IStructuredModel) (in org.eclipse.wst.xml.ui.internal.spelling.SpellcheckDelegateAdapterFactory)
silently suppresses spell checking for any text node whose parent element has no CMElementDeclaration in the resolved grammar — which includes every element that only matches an xsd:any wildcard. For a schema that uses wildcards to allow open-ended content (the Maven POM 4.0.0 XSD's <properties> element being a very common real-world example), this means none of the text inside that element is ever spell checked, even though the element is perfectly valid per the schema and its content is exactly the kind of free-form text spell checking exists for.
Where
public boolean shouldSpellcheck(int offset, IStructuredModel model) {
boolean shouldSpellcheck = true;
IndexedRegion region = model.getIndexedRegion(offset);
if (region != null) {
shouldSpellcheck = region instanceof Comment;
if (!shouldSpellcheck && region instanceof Text) {
final Node parent = ((Text) (region)).getParentNode();
if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) {
final ModelQuery mq = ModelQueryUtil.getModelQuery(parent.getOwnerDocument());
if (mq != null) {
final CMElementDeclaration decl = mq.getCMElementDeclaration((Element) parent);
if (decl != null) {
final CMDataType type = decl.getDataType();
shouldSpellcheck = type == null || type.getEnumeratedValues() == null || type.getEnumeratedValues().length == 0;
}
// decl == null (e.g. only matched via xsd:any) -> shouldSpellcheck stays false, silently
}
// mq == null -> shouldSpellcheck also stays false
}
}
}
return shouldSpellcheck;
}
(xml/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/spelling/SpellcheckDelegateAdapterFactory.java)
When mq.getCMElementDeclaration((Element) parent) returns null — which is exactly what happens for an element that's only reachable through an xsd:any wildcard, since there's no dedicated declaration for it — the method falls through without ever setting shouldSpellcheck back to true. The same happens if ModelQueryUtil.getModelQuery(...) itself returns null. Both cases are indistinguishable from "this text genuinely shouldn't be spell-checked" even though neither implies that.
This is invoked from SpellcheckStrategy.isInterestingProblem(SpellingProblem) (org.eclipse.wst.sse.ui), which is the last filter a SpellingProblem passes through before becoming a visible annotation — the underlying ISpellingEngine (any of them, built-in or a custom-contributed one) still computes and reports the problem correctly; it's discarded here, silently, with no logging and no way to see it just from watching the editor.
Reproduction
-
Open this pom.xml in the XML editor:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>example</groupId>
<artifactId>example</artifactId>
<version>1.0</version>
<properties>
<my.custom.property>wombatz</my.custom.property>
</properties>
<name>wombatz</name>
</project>
-
Enable spell checking (Preferences > General > Editors > Text Editors > Spelling) with a dictionary that will flag "wombatz" as misspelled.
-
Observe: wombatz inside <name> gets underlined (name has an explicit CMElementDeclaration with a non-enumerated string type in the POM 4.0.0 XSD). wombatz inside <my.custom.property> does not — even though it's the identical word, in the same file, checked by the same engine.
-
Confirm the engine really did compute+report it: open the same file a second time via Open With > Plain Text Editor. Since it shares the same IAnnotationModel with the already-open XML editor, both editors immediately show the <my.custom.property> annotation too — proving it was always being calculated correctly and only withheld by XMLSpellcheckDelegate.
Expected
Text under an element that's valid per the schema (even if only via a wildcard) should be spell-checked the same as any other element with a non enumerated string content type — or, if suppressing wildcard-matched content is intentional, that should be a distinguishable, documented case (and ideally configurable), not indistinguishable from "no grammar at all" or logged nowhere.
Suggested fix
-
Default shouldSpellcheck to true when decl == null (unknown/wildcard element) instead of leaving it false, mirroring how a document with no grammar at all is presumably still spell-checked for its Text nodes elsewhere.
-
Or, more precisely: the content model does expose this distinction, just not through the method this code calls. getCMElementDeclaration(Element) can only ever return a CMElementDeclaration, so it comes back null for anything only reachable through an xsd:any wildcard — that wildcard is represented separately as CMAnyElement (CMNode.getNodeType() == CMNode.ANY_ELEMENT), which getCMElementDeclaration has no way to surface. ModelQuery.getCMNode(Node) returns the broader CMNode type and would let this code tell the two cases apart:
final CMNode node = mq.getCMNode((Element) parent);
if (node != null) {
if (node.getNodeType() == CMNode.ANY_ELEMENT) {
// Matched only via an xsd:any (or DTD ANY) wildcard — there's no
// dedicated declaration, but the element is still valid content
// here, so its text is exactly the free-form case spell checking
// is for.
shouldSpellcheck = true;
} else if (node instanceof CMElementDeclaration) {
final CMDataType type = ((CMElementDeclaration) node).getDataType();
shouldSpellcheck = type == null || type.getEnumeratedValues() == null || type.getEnumeratedValues().length == 0;
}
}
in place of the current getCMElementDeclaration call, keeping the existing enumerated-type check for genuinely declared elements and only changing the outcome for the ANY_ELEMENT case.
Environment
- Eclipse 4.40 (2026-06)
- org.eclipse.wst.xml.ui 1.2.900.v202510300114
- org.eclipse.wst.sse.ui 1.7.1200.v202510300114
Summary
XMLSpellcheckDelegate.shouldSpellcheck(int, IStructuredModel)(inorg.eclipse.wst.xml.ui.internal.spelling.SpellcheckDelegateAdapterFactory)silently suppresses spell checking for any text node whose parent element has no
CMElementDeclarationin the resolved grammar — which includes every element that only matches anxsd:anywildcard. For a schema that uses wildcards to allow open-ended content (the Maven POM 4.0.0 XSD's<properties>element being a very common real-world example), this means none of the text inside that element is ever spell checked, even though the element is perfectly valid per the schema and its content is exactly the kind of free-form text spell checking exists for.Where
(
xml/bundles/org.eclipse.wst.xml.ui/src/org/eclipse/wst/xml/ui/internal/spelling/SpellcheckDelegateAdapterFactory.java)When
mq.getCMElementDeclaration((Element) parent)returnsnull— which is exactly what happens for an element that's only reachable through anxsd:anywildcard, since there's no dedicated declaration for it — the method falls through without ever settingshouldSpellcheckback totrue. The same happens ifModelQueryUtil.getModelQuery(...)itself returnsnull. Both cases are indistinguishable from "this text genuinely shouldn't be spell-checked" even though neither implies that.This is invoked from
SpellcheckStrategy.isInterestingProblem(SpellingProblem)(org.eclipse.wst.sse.ui), which is the last filter aSpellingProblempasses through before becoming a visible annotation — the underlyingISpellingEngine(any of them, built-in or a custom-contributed one) still computes and reports the problem correctly; it's discarded here, silently, with no logging and no way to see it just from watching the editor.Reproduction
Open this
pom.xmlin the XML editor:Enable spell checking (Preferences > General > Editors > Text Editors > Spelling) with a dictionary that will flag "wombatz" as misspelled.
Observe:
wombatzinside<name>gets underlined (namehas an explicitCMElementDeclarationwith a non-enumerated string type in the POM 4.0.0 XSD).wombatzinside<my.custom.property>does not — even though it's the identical word, in the same file, checked by the same engine.Confirm the engine really did compute+report it: open the same file a second time via Open With > Plain Text Editor. Since it shares the same
IAnnotationModelwith the already-open XML editor, both editors immediately show the<my.custom.property>annotation too — proving it was always being calculated correctly and only withheld byXMLSpellcheckDelegate.Expected
Text under an element that's valid per the schema (even if only via a wildcard) should be spell-checked the same as any other element with a non enumerated string content type — or, if suppressing wildcard-matched content is intentional, that should be a distinguishable, documented case (and ideally configurable), not indistinguishable from "no grammar at all" or logged nowhere.
Suggested fix
Default
shouldSpellchecktotruewhendecl == null(unknown/wildcard element) instead of leaving itfalse, mirroring how a document with no grammar at all is presumably still spell-checked for itsTextnodes elsewhere.Or, more precisely: the content model does expose this distinction, just not through the method this code calls.
getCMElementDeclaration(Element)can only ever return aCMElementDeclaration, so it comes backnullfor anything only reachable through anxsd:anywildcard — that wildcard is represented separately asCMAnyElement(CMNode.getNodeType() == CMNode.ANY_ELEMENT), whichgetCMElementDeclarationhas no way to surface.ModelQuery.getCMNode(Node)returns the broaderCMNodetype and would let this code tell the two cases apart:in place of the current
getCMElementDeclarationcall, keeping the existing enumerated-type check for genuinely declared elements and only changing the outcome for theANY_ELEMENTcase.Environment