source: trunk/src/xmlpatterns/schema/qxsdschemachecker.cpp@ 597

Last change on this file since 597 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

  • Property svn:eol-style set to native
File size: 109.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtXmlPatterns module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qxsdschemachecker_p.h"
43
44#include "qderivedinteger_p.h"
45#include "qderivedstring_p.h"
46#include "qpatternplatform_p.h"
47#include "qqnamevalue_p.h"
48#include "qsourcelocationreflection_p.h"
49#include "qvaluefactory_p.h"
50#include "qxsdattributereference_p.h"
51#include "qxsdparticlechecker_p.h"
52#include "qxsdreference_p.h"
53#include "qxsdschemacontext_p.h"
54#include "qxsdschemahelper_p.h"
55#include "qxsdschemaparsercontext_p.h"
56#include "qxsdschematypesfactory_p.h"
57#include "qxsdtypechecker_p.h"
58
59#include "qxsdschemachecker_helper.cpp"
60
61QT_BEGIN_NAMESPACE
62
63using namespace QPatternist;
64
65XsdSchemaChecker::XsdSchemaChecker(const QExplicitlySharedDataPointer<XsdSchemaContext> &context, const XsdSchemaParserContext *parserContext)
66 : m_context(context)
67 , m_namePool(parserContext->namePool())
68 , m_schema(parserContext->schema())
69{
70 setupAllowedAtomicFacets();
71}
72
73XsdSchemaChecker::~XsdSchemaChecker()
74{
75}
76
77/*
78 * This method is called after the resolver has set the base type for every
79 * type and information about deriavtion and 'is simple type vs. is complex type'
80 * are available.
81 */
82void XsdSchemaChecker::basicCheck()
83{
84 // first check that there is no circular inheritance, only the
85 // wxsSuperType is used here
86 checkBasicCircularInheritances();
87
88 // check the basic constraints like simple type can not inherit from complex type etc.
89 checkBasicSimpleTypeConstraints();
90 checkBasicComplexTypeConstraints();
91}
92
93void XsdSchemaChecker::check()
94{
95 checkCircularInheritances();
96 checkInheritanceRestrictions();
97 checkSimpleDerivationRestrictions();
98 checkSimpleTypeConstraints();
99 checkComplexTypeConstraints();
100 checkDuplicatedAttributeUses();
101
102 checkElementConstraints();
103 checkAttributeConstraints();
104 checkAttributeUseConstraints();
105// checkElementDuplicates();
106}
107
108void XsdSchemaChecker::addComponentLocationHash(const ComponentLocationHash &hash)
109{
110 m_componentLocationHash.unite(hash);
111}
112
113/**
114 * Checks whether the @p otherType is the same as @p myType or if one of its
115 * ancestors is the same as @p myType.
116 */
117static bool matchesType(const SchemaType::Ptr &myType, const SchemaType::Ptr &otherType, QSet<SchemaType::Ptr> visitedTypes)
118{
119 bool retval = false;
120
121 if (otherType) {
122 if (visitedTypes.contains(otherType)) {
123 return true;
124 } else {
125 visitedTypes.insert(otherType);
126 }
127 // simple types can have different varieties, so we have to check each of them
128 if (otherType->isSimpleType()) {
129 const XsdSimpleType::Ptr simpleType = otherType;
130 if (simpleType->category() == XsdSimpleType::SimpleTypeAtomic) {
131 // for atomic type we use the same test as in SchemaType::wxsTypeMatches
132 retval = (myType == simpleType ? true : matchesType(myType, simpleType->wxsSuperType(), visitedTypes));
133 } else if (simpleType->category() == XsdSimpleType::SimpleTypeList) {
134 // for list type we test against the itemType property
135 retval = (myType == simpleType->itemType() ? true : matchesType(myType, simpleType->itemType()->wxsSuperType(), visitedTypes));
136 } else if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) {
137 // for union type we test against each member type
138 const XsdSimpleType::List members = simpleType->memberTypes();
139 for (int i = 0; i < members.count(); ++i) {
140 if (myType == members.at(i) ? true : matchesType(myType, members.at(i)->wxsSuperType(), visitedTypes)) {
141 retval = true;
142 break;
143 }
144 }
145 } else {
146 // reached xsAnySimple type whichs category is None
147 retval = false;
148 }
149 } else {
150 // if no simple type we handle it like in SchemaType::wxsTypeMatches
151 retval = (myType == otherType ? true : matchesType(myType, otherType->wxsSuperType(), visitedTypes));
152 }
153 } else // if otherType is null it doesn't match
154 retval = false;
155
156 return retval;
157}
158
159/**
160 * Checks whether there is a circular inheritance for the union inheritance.
161 */
162static bool hasCircularUnionInheritance(const XsdSimpleType::Ptr &type, const SchemaType::Ptr &otherType, NamePool::Ptr &namePool)
163{
164 if (type == otherType) {
165 return true;
166 }
167
168 if (!otherType->isSimpleType() || !otherType->isDefinedBySchema()) {
169 return false;
170 }
171
172 const XsdSimpleType::Ptr simpleOtherType = otherType;
173
174 if (simpleOtherType->category() == XsdSimpleType::SimpleTypeUnion) {
175 const XsdSimpleType::List memberTypes = simpleOtherType->memberTypes();
176 for (int i = 0; i < memberTypes.count(); ++i) {
177 if (otherType->wxsSuperType() == type) {
178 return true;
179 }
180 if (hasCircularUnionInheritance(type, memberTypes.at(i), namePool)) {
181 return true;
182 }
183 }
184 }
185
186 return false;
187}
188
189static inline bool wxsTypeMatches(const SchemaType::Ptr &type, const SchemaType::Ptr &otherType, QSet<SchemaType::Ptr> &visitedTypes, SchemaType::Ptr &conflictingType)
190{
191 if (!otherType)
192 return false;
193
194 if (visitedTypes.contains(otherType)) { // inheritance loop detected
195 conflictingType = otherType;
196 return true;
197 } else {
198 visitedTypes.insert(otherType);
199 }
200
201 if (type == otherType)
202 return true;
203
204 return wxsTypeMatches(type, otherType->wxsSuperType(), visitedTypes, conflictingType);
205}
206
207void XsdSchemaChecker::checkBasicCircularInheritances()
208{
209 // check all global types...
210 SchemaType::List types = m_schema->types();
211
212 // .. and anonymous types
213 types << m_schema->anonymousTypes();
214
215 for (int i = 0; i < types.count(); ++i) {
216 const SchemaType::Ptr type = types.at(i);
217 const QSourceLocation location = sourceLocationForType(type);
218
219 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 3)
220
221 // check normal base type inheritance
222 QSet<SchemaType::Ptr> visitedTypes;
223 SchemaType::Ptr conflictingType;
224
225 if (wxsTypeMatches(type, type->wxsSuperType(), visitedTypes, conflictingType)) {
226 if (conflictingType)
227 m_context->error(QtXmlPatterns::tr("%1 has inheritance loop in its base type %2.")
228 .arg(formatType(m_namePool, type))
229 .arg(formatType(m_namePool, conflictingType)),
230 XsdSchemaContext::XSDError, location);
231 else
232 m_context->error(QtXmlPatterns::tr("Circular inheritance of base type %1.").arg(formatType(m_namePool, type)), XsdSchemaContext::XSDError, location);
233
234 return;
235 }
236 }
237}
238
239void XsdSchemaChecker::checkCircularInheritances()
240{
241 // check all global types...
242 SchemaType::List types = m_schema->types();
243
244 // .. and anonymous types
245 types << m_schema->anonymousTypes();
246
247 for (int i = 0; i < types.count(); ++i) {
248 const SchemaType::Ptr type = types.at(i);
249 const QSourceLocation location = sourceLocationForType(type);
250
251 // @see http://www.w3.org/TR/xmlschema11-1/#ct-props-correct 3)
252
253 // check normal base type inheritance
254 QSet<SchemaType::Ptr> visitedTypes;
255 if (matchesType(type, type->wxsSuperType(), visitedTypes)) {
256 m_context->error(QtXmlPatterns::tr("Circular inheritance of base type %1.").arg(formatType(m_namePool, type)), XsdSchemaContext::XSDError, location);
257 return;
258 }
259
260 // check union member inheritance
261 if (type->isSimpleType() && type->isDefinedBySchema()) {
262 const XsdSimpleType::Ptr simpleType = type;
263 if (simpleType->category() == XsdSimpleType::SimpleTypeUnion) {
264 const XsdSimpleType::List memberTypes = simpleType->memberTypes();
265 for (int j = 0; j < memberTypes.count(); ++j) {
266 if (hasCircularUnionInheritance(simpleType, memberTypes.at(j), m_namePool)) {
267 m_context->error(QtXmlPatterns::tr("Circular inheritance of union %1.").arg(formatType(m_namePool, type)), XsdSchemaContext::XSDError, location);
268 return;
269 }
270 }
271 }
272 }
273 }
274}
275
276void XsdSchemaChecker::checkInheritanceRestrictions()
277{
278 // check all global types...
279 SchemaType::List types = m_schema->types();
280
281 // .. and anonymous types
282 types << m_schema->anonymousTypes();
283
284 for (int i = 0; i < types.count(); ++i) {
285 const SchemaType::Ptr type = types.at(i);
286 const QSourceLocation location = sourceLocationForType(type);
287
288 // check inheritance restrictions given by final property of base class
289 const SchemaType::Ptr baseType = type->wxsSuperType();
290 if (baseType->isDefinedBySchema()) {
291 if ((type->derivationMethod() == SchemaType::DerivationRestriction) && (baseType->derivationConstraints() & SchemaType::RestrictionConstraint)) {
292 m_context->error(QtXmlPatterns::tr("%1 is not allowed to derive from %2 by restriction as the latter defines it as final.")
293 .arg(formatType(m_namePool, type))
294 .arg(formatType(m_namePool, baseType)), XsdSchemaContext::XSDError, location);
295 return;
296 } else if ((type->derivationMethod() == SchemaType::DerivationExtension) && (baseType->derivationConstraints() & SchemaType::ExtensionConstraint)) {
297 m_context->error(QtXmlPatterns::tr("%1 is not allowed to derive from %2 by extension as the latter defines it as final.")
298 .arg(formatType(m_namePool, type))
299 .arg(formatType(m_namePool, baseType)), XsdSchemaContext::XSDError, location);
300 return;
301 }
302 }
303 }
304}
305
306void XsdSchemaChecker::checkBasicSimpleTypeConstraints()
307{
308 // check all global types...
309 SchemaType::List types = m_schema->types();
310
311 // .. and anonymous types
312 types << m_schema->anonymousTypes();
313
314 for (int i = 0; i < types.count(); ++i) {
315 const SchemaType::Ptr type = types.at(i);
316
317 if (!type->isSimpleType())
318 continue;
319
320 const XsdSimpleType::Ptr simpleType = type;
321
322 const QSourceLocation location = sourceLocation(simpleType);
323
324 // check inheritance restrictions of simple type defined by schema constraints
325 const SchemaType::Ptr baseType = simpleType->wxsSuperType();
326
327 if (baseType->isComplexType() && (simpleType->name(m_namePool) != BuiltinTypes::xsAnySimpleType->name(m_namePool))) {
328 m_context->error(QtXmlPatterns::tr("Base type of simple type %1 cannot be complex type %2.")
329 .arg(formatType(m_namePool, simpleType))
330 .arg(formatType(m_namePool, baseType)),
331 XsdSchemaContext::XSDError, location);
332 return;
333 }
334
335 if (baseType == BuiltinTypes::xsAnyType) {
336 if (type->name(m_namePool) != BuiltinTypes::xsAnySimpleType->name(m_namePool)) {
337 m_context->error(QtXmlPatterns::tr("Simple type %1 cannot have direct base type %2.")
338 .arg(formatType(m_namePool, simpleType))
339 .arg(formatType(m_namePool, BuiltinTypes::xsAnyType)),
340 XsdSchemaContext::XSDError, location);
341 return;
342 }
343 }
344 }
345}
346
347void XsdSchemaChecker::checkSimpleTypeConstraints()
348{
349 // check all global types...
350 SchemaType::List types = m_schema->types();
351
352 // .. and anonymous types
353 types << m_schema->anonymousTypes();
354
355 for (int i = 0; i < types.count(); ++i) {
356 const SchemaType::Ptr type = types.at(i);
357
358 if (!type->isSimpleType())
359 continue;
360
361 const XsdSimpleType::Ptr simpleType = type;
362
363 const QSourceLocation location = sourceLocation(simpleType);
364
365 if (simpleType->category() == XsdSimpleType::None) {
366 // additional checks
367 // check that no user defined type has xs:AnySimpleType as base type (except xs:AnyAtomicType)
368 if (simpleType->wxsSuperType()->name(m_namePool) == BuiltinTypes::xsAnySimpleType->name(m_namePool)) {
369 if (simpleType->name(m_namePool) != BuiltinTypes::xsAnyAtomicType->name(m_namePool)) {
370 m_context->error(QtXmlPatterns::tr("Simple type %1 is not allowed to have base type %2.")
371 .arg(formatType(m_namePool, simpleType))
372 .arg(formatType(m_namePool, simpleType->wxsSuperType())),
373 XsdSchemaContext::XSDError, location);
374 return;
375 }
376 }
377 // check that no user defined type has xs:AnyAtomicType as base type
378 if (simpleType->wxsSuperType()->name(m_namePool) == BuiltinTypes::xsAnyAtomicType->name(m_namePool)) {
379 m_context->error(QtXmlPatterns::tr("Simple type %1 is not allowed to have base type %2.")
380 .arg(formatType(m_namePool, simpleType))
381 .arg(formatType(m_namePool, simpleType->wxsSuperType())),
382 XsdSchemaContext::XSDError, location);
383 return;
384 }
385 }
386
387 // @see http://www.w3.org/TR/xmlschema11-1/#d0e37310
388 if (simpleType->category() == XsdSimpleType::SimpleTypeAtomic) {
389 // 1.1
390 if ((simpleType->wxsSuperType()->category() != XsdSimpleType::SimpleTypeAtomic) && (simpleType->name(m_namePool) != BuiltinTypes::xsAnyAtomicType->name(m_namePool))) {
391 m_context->error(QtXmlPatterns::tr("Simple type %1 can only have simple atomic type as base type.")
392 .arg(formatType(m_namePool, simpleType)),
393 XsdSchemaContext::XSDError, location);
394 }
395 // 1.2
396 if (simpleType->wxsSuperType()->derivationConstraints() & SchemaType::RestrictionConstraint) {
397 m_context->error(QtXmlPatterns::tr("Simple type %1 cannot derive from %2 as the latter defines restriction as final.")
398 .arg(formatType(m_namePool, simpleType->wxsSuperType()))
399 .arg(formatType(m_namePool, simpleType)),
400 XsdSchemaContext::XSDError, location);
401 }
402
403 // 1.3
404 // checked by checkConstrainingFacets already
405 } else if (simpleType->category() == XsdSimpleType::SimpleTypeList) {
406 const AnySimpleType::Ptr itemType = simpleType->itemType();
407
408 // 2.1 or @see http://www.w3.org/TR/xmlschema-2/#cos-list-of-atomic
409 if (itemType->category() != SchemaType::SimpleTypeAtomic && itemType->category() != SchemaType::SimpleTypeUnion) {
410 m_context->error(QtXmlPatterns::tr("Variety of item type of %1 must be either atomic or union.").arg(formatType(m_namePool, simpleType)), XsdSchemaContext::XSDError, location);
411 return;
412 }
413
414 // 2.1 second part
415 if (itemType->category() == SchemaType::SimpleTypeUnion && itemType->isDefinedBySchema()) {
416 const XsdSimpleType::Ptr simpleItemType = itemType;
417 const AnySimpleType::List memberTypes = simpleItemType->memberTypes();
418 for (int j = 0; j < memberTypes.count(); ++j) {
419 if (memberTypes.at(j)->category() != SchemaType::SimpleTypeAtomic) {
420 m_context->error(QtXmlPatterns::tr("Variety of member types of %1 must be atomic.").arg(formatType(m_namePool, simpleItemType)), XsdSchemaContext::XSDError, location);
421 return;
422 }
423 }
424 }
425
426 // 2.2.1
427 if (simpleType->wxsSuperType()->name(m_namePool) == BuiltinTypes::xsAnySimpleType->name(m_namePool)) {
428 if (itemType->isSimpleType() && itemType->isDefinedBySchema()) {
429 const XsdSimpleType::Ptr simpleItemType = itemType;
430
431 // 2.2.1.1
432 if (simpleItemType->derivationConstraints() & XsdSimpleType::ListConstraint) {
433 m_context->error(QtXmlPatterns::tr("%1 is not allowed to derive from %2 by list as the latter defines it as final.")
434 .arg(formatType(m_namePool, simpleType))
435 .arg(formatType(m_namePool, simpleItemType)), XsdSchemaContext::XSDError, location);
436 return;
437 }
438
439 // 2.2.1.2
440 const XsdFacet::Hash facets = simpleType->facets();
441 XsdFacet::HashIterator it(facets);
442
443 bool invalidFacetFound = false;
444 while (it.hasNext()) {
445 it.next();
446 if (it.key() != XsdFacet::WhiteSpace) {
447 invalidFacetFound = true;
448 break;
449 }
450 }
451
452 if (invalidFacetFound) {
453 m_context->error(QtXmlPatterns::tr("Simple type %1 is only allowed to have %2 facet.")
454 .arg(formatType(m_namePool, simpleType))
455 .arg(formatKeyword("whiteSpace")),
456 XsdSchemaContext::XSDError, location);
457 return;
458 }
459 }
460 } else { // 2.2.2
461 // 2.2.2.1
462 if (simpleType->wxsSuperType()->category() != XsdSimpleType::SimpleTypeList) {
463 m_context->error(QtXmlPatterns::tr("Base type of simple type %1 must have variety of type list.").arg(formatType(m_namePool, simpleType)), XsdSchemaContext::XSDError, location);
464 return;
465 }
466
467 // 2.2.2.2
468 if (simpleType->wxsSuperType()->derivationConstraints() & SchemaType::RestrictionConstraint) {
469 m_context->error(QtXmlPatterns::tr("Base type of simple type %1 has defined derivation by restriction as final.").arg(formatType(m_namePool, simpleType)), XsdSchemaContext::XSDError, location);
470 return;
471 }
472
473 // 2.2.2.3
474 if (!XsdSchemaHelper::isSimpleDerivationOk(itemType, XsdSimpleType::Ptr(simpleType->wxsSuperType())->itemType(), SchemaType::DerivationConstraints())) {
475 m_context->error(QtXmlPatterns::tr("Item type of base type does not match item type of %1.").arg(formatType(m_namePool, simpleType)), XsdSchemaContext::XSDError, location);
476 return;
477 }
478
479 // 2.2.2.4
480 const XsdFacet::Hash facets = simpleType->facets();
481 XsdFacet::HashIterator it(facets);
482
483 bool invalidFacetFound = false;
484 XsdFacet::Type invalidFacetType = XsdFacet::None;
485 while (it.hasNext()) {
486 it.next();
487 const XsdFacet::Type facetType = it.key();
488 if (facetType != XsdFacet::Length &&
489 facetType != XsdFacet::MinimumLength &&
490 facetType != XsdFacet::MaximumLength &&
491 facetType != XsdFacet::WhiteSpace &&
492 facetType != XsdFacet::Pattern &&
493 facetType != XsdFacet::Enumeration) {
494 invalidFacetType = facetType;
495 invalidFacetFound = true;
496 break;
497 }
498 }
499
500 if (invalidFacetFound) {
501 m_context->error(QtXmlPatterns::tr("Simple type %1 contains not allowed facet type %2.")
502 .arg(formatType(m_namePool, simpleType))
503 .arg(formatKeyword(XsdFacet::typeName(invalidFacetType))),
504 XsdSchemaContext::XSDError, location);
505 return;
506 }
507
508 // 2.2.2.5