diff --git a/config/identical-files.json b/config/identical-files.json index 66d5c1457a8..a8b1368f1af 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -251,10 +251,6 @@ "cpp/ql/src/Security/CWE/CWE-020/SafeExternalAPIFunction.qll", "cpp/ql/src/Security/CWE/CWE-020/ir/SafeExternalAPIFunction.qll" ], - "XML": [ - "java/ql/lib/semmle/code/xml/XML.qll", - "python/ql/lib/semmle/python/xml/XML.qll" - ], "DuplicationProblems.inc.qhelp": [ "cpp/ql/src/Metrics/Files/DuplicationProblems.inc.qhelp", "javascript/ql/src/Metrics/DuplicationProblems.inc.qhelp", diff --git a/java/ql/lib/qlpack.yml b/java/ql/lib/qlpack.yml index 15b4982d41e..750697a2548 100644 --- a/java/ql/lib/qlpack.yml +++ b/java/ql/lib/qlpack.yml @@ -14,6 +14,7 @@ dependencies: codeql/tutorial: ${workspace} codeql/typetracking: ${workspace} codeql/util: ${workspace} + codeql/xml: ${workspace} dataExtensions: - ext/*.model.yml - ext/generated/*.model.yml diff --git a/java/ql/lib/semmle/code/java/frameworks/spring/SpringBean.qll b/java/ql/lib/semmle/code/java/frameworks/spring/SpringBean.qll index bbb6adf72f3..a53cbf67090 100644 --- a/java/ql/lib/semmle/code/java/frameworks/spring/SpringBean.qll +++ b/java/ql/lib/semmle/code/java/frameworks/spring/SpringBean.qll @@ -19,7 +19,8 @@ class SpringBean extends SpringXmlElement { not this.getNamespace().getUri() = "http://camel.apache.org/schema/spring" } - override string toString() { result = this.getBeanIdentifier() } + /** Gets a printable representation of this XML element. */ + string toString() { result = this.getBeanIdentifier() } /** * Holds if this element is a top-level bean definition. diff --git a/java/ql/lib/semmle/code/java/frameworks/spring/SpringProperty.qll b/java/ql/lib/semmle/code/java/frameworks/spring/SpringProperty.qll index 06d5daefaa1..a83eeed13fa 100644 --- a/java/ql/lib/semmle/code/java/frameworks/spring/SpringProperty.qll +++ b/java/ql/lib/semmle/code/java/frameworks/spring/SpringProperty.qll @@ -9,7 +9,8 @@ import semmle.code.java.frameworks.spring.SpringValue class SpringProperty extends SpringXmlElement { SpringProperty() { this.getName() = "property" } - override string toString() { result = this.getPropertyName() } + /** Gets a printable representation of this XML element. */ + string toString() { result = this.getPropertyName() } /** Gets the value of the `name` attribute. */ string getPropertyName() { result = this.getAttributeValue("name") } diff --git a/java/ql/lib/semmle/code/xml/Ant.qll b/java/ql/lib/semmle/code/xml/Ant.qll index 8d4737620a4..59cd2889096 100644 --- a/java/ql/lib/semmle/code/xml/Ant.qll +++ b/java/ql/lib/semmle/code/xml/Ant.qll @@ -9,7 +9,7 @@ class AntTarget extends XmlElement { AntTarget() { super.getName() = "target" } /** Gets the name of this Ant target. */ - override string getName() { result = this.getAttributeValue("name") } + string getName() { result = this.getAttributeValue("name") } /** * Gets a string containing the dependencies of this Ant target, diff --git a/java/ql/lib/semmle/code/xml/XML.qll b/java/ql/lib/semmle/code/xml/XML.qll index 65bdd7b7cc1..54157809260 100644 --- a/java/ql/lib/semmle/code/xml/XML.qll +++ b/java/ql/lib/semmle/code/xml/XML.qll @@ -3,305 +3,67 @@ */ import semmle.files.FileSystem +private import codeql.xml.Xml -private class TXmlLocatable = - @xmldtd or @xmlelement or @xmlattribute or @xmlnamespace or @xmlcomment or @xmlcharacters; +private module Input implements InputSig { + class XmlLocatableBase = @xmllocatable or @xmlnamespaceable; -/** An XML element that has a location. */ -class XmlLocatable extends @xmllocatable, TXmlLocatable { - /** Gets the source location for this element. */ - Location getLocation() { xmllocations(this, result) } + predicate xmllocations_(XmlLocatableBase e, Location loc) { xmllocations(e, loc) } - /** - * Holds if this element is at the specified location. - * The location spans column `startcolumn` of line `startline` to - * column `endcolumn` of line `endline` in file `filepath`. - * For more information, see - * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). - */ - predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn + class XmlParentBase = @xmlparent; + + class XmlNamespaceableBase = @xmlnamespaceable; + + class XmlElementBase = @xmlelement; + + class XmlFileBase = File; + + predicate xmlEncoding_(XmlFileBase f, string enc) { xmlEncoding(f, enc) } + + class XmlDtdBase = @xmldtd; + + predicate xmlDTDs_(XmlDtdBase e, string root, string publicId, string systemId, XmlFileBase file) { + xmlDTDs(e, root, publicId, systemId, file) + } + + predicate xmlElements_( + XmlElementBase e, string name, XmlParentBase parent, int idx, XmlFileBase file ) { - exists(File f, Location l | l = this.getLocation() | - locations_default(l, f, startline, startcolumn, endline, endcolumn) and - filepath = f.getAbsolutePath() - ) + xmlElements(e, name, parent, idx, file) } - /** Gets a textual representation of this element. */ - string toString() { none() } // overridden in subclasses -} + class XmlAttributeBase = @xmlattribute; -/** - * An `XmlParent` is either an `XmlElement` or an `XmlFile`, - * both of which can contain other elements. - */ -class XmlParent extends @xmlparent { - XmlParent() { - // explicitly restrict `this` to be either an `XmlElement` or an `XmlFile`; - // the type `@xmlparent` currently also includes non-XML files - this instanceof @xmlelement or xmlEncoding(this, _) + predicate xmlAttrs_( + XmlAttributeBase e, XmlElementBase elementid, string name, string value, int idx, + XmlFileBase file + ) { + xmlAttrs(e, elementid, name, value, idx, file) } - /** - * Gets a printable representation of this XML parent. - * (Intended to be overridden in subclasses.) - */ - string getName() { none() } // overridden in subclasses + class XmlNamespaceBase = @xmlnamespace; - /** Gets the file to which this XML parent belongs. */ - XmlFile getFile() { result = this or xmlElements(this, _, _, _, result) } - - /** Gets the child element at a specified index of this XML parent. */ - XmlElement getChild(int index) { xmlElements(result, _, this, index, _) } - - /** Gets a child element of this XML parent. */ - XmlElement getAChild() { xmlElements(result, _, this, _, _) } - - /** Gets a child element of this XML parent with the given `name`. */ - XmlElement getAChild(string name) { xmlElements(result, _, this, _, _) and result.hasName(name) } - - /** Gets a comment that is a child of this XML parent. */ - XmlComment getAComment() { xmlComments(result, _, this, _) } - - /** Gets a character sequence that is a child of this XML parent. */ - XmlCharacters getACharactersSet() { xmlChars(result, _, this, _, _, _) } - - /** Gets the depth in the tree. (Overridden in XmlElement.) */ - int getDepth() { result = 0 } - - /** Gets the number of child XML elements of this XML parent. */ - int getNumberOfChildren() { result = count(XmlElement e | xmlElements(e, _, this, _, _)) } - - /** Gets the number of places in the body of this XML parent where text occurs. */ - int getNumberOfCharacterSets() { result = count(int pos | xmlChars(_, _, this, pos, _, _)) } - - /** - * Gets the result of appending all the character sequences of this XML parent from - * left to right, separated by a space. - */ - string allCharactersString() { - result = - concat(string chars, int pos | xmlChars(_, chars, this, pos, _, _) | chars, " " order by pos) + predicate xmlNs_(XmlNamespaceBase e, string prefixName, string uri, XmlFileBase file) { + xmlNs(e, prefixName, uri, file) } - /** Gets the text value contained in this XML parent. */ - string getTextValue() { result = this.allCharactersString() } + predicate xmlHasNs_(XmlNamespaceableBase e, XmlNamespaceBase ns, XmlFileBase file) { + xmlHasNs(e, ns, file) + } - /** Gets a printable representation of this XML parent. */ - string toString() { result = this.getName() } -} + class XmlCommentBase = @xmlcomment; -/** An XML file. */ -class XmlFile extends XmlParent, File { - XmlFile() { xmlEncoding(this, _) } + predicate xmlComments_(XmlCommentBase e, string text, XmlParentBase parent, XmlFileBase file) { + xmlComments(e, text, parent, file) + } - /** Gets a printable representation of this XML file. */ - override string toString() { result = this.getName() } + class XmlCharactersBase = @xmlcharacters; - /** Gets the name of this XML file. */ - override string getName() { result = File.super.getAbsolutePath() } - - /** Gets the encoding of this XML file. */ - string getEncoding() { xmlEncoding(this, result) } - - /** Gets the XML file itself. */ - override XmlFile getFile() { result = this } - - /** Gets a top-most element in an XML file. */ - XmlElement getARootElement() { result = this.getAChild() } - - /** Gets a DTD associated with this XML file. */ - XmlDtd getADtd() { xmlDTDs(result, _, _, _, this) } -} - -/** - * An XML document type definition (DTD). - * - * Example: - * - * ``` - * - * - * - * ``` - */ -class XmlDtd extends XmlLocatable, @xmldtd { - /** Gets the name of the root element of this DTD. */ - string getRoot() { xmlDTDs(this, result, _, _, _) } - - /** Gets the public ID of this DTD. */ - string getPublicId() { xmlDTDs(this, _, result, _, _) } - - /** Gets the system ID of this DTD. */ - string getSystemId() { xmlDTDs(this, _, _, result, _) } - - /** Holds if this DTD is public. */ - predicate isPublic() { not xmlDTDs(this, _, "", _, _) } - - /** Gets the parent of this DTD. */ - XmlParent getParent() { xmlDTDs(this, _, _, _, result) } - - override string toString() { - this.isPublic() and - result = this.getRoot() + " PUBLIC '" + this.getPublicId() + "' '" + this.getSystemId() + "'" - or - not this.isPublic() and - result = this.getRoot() + " SYSTEM '" + this.getSystemId() + "'" + predicate xmlChars_( + XmlCharactersBase e, string text, XmlParentBase parent, int idx, int isCDATA, XmlFileBase file + ) { + xmlChars(e, text, parent, idx, isCDATA, file) } } -/** - * An XML element in an XML file. - * - * Example: - * - * ``` - * - * - * ``` - */ -class XmlElement extends @xmlelement, XmlParent, XmlLocatable { - /** Holds if this XML element has the given `name`. */ - predicate hasName(string name) { name = this.getName() } - - /** Gets the name of this XML element. */ - override string getName() { xmlElements(this, result, _, _, _) } - - /** Gets the XML file in which this XML element occurs. */ - override XmlFile getFile() { xmlElements(this, _, _, _, result) } - - /** Gets the parent of this XML element. */ - XmlParent getParent() { xmlElements(this, _, result, _, _) } - - /** Gets the index of this XML element among its parent's children. */ - int getIndex() { xmlElements(this, _, _, result, _) } - - /** Holds if this XML element has a namespace. */ - predicate hasNamespace() { xmlHasNs(this, _, _) } - - /** Gets the namespace of this XML element, if any. */ - XmlNamespace getNamespace() { xmlHasNs(this, result, _) } - - /** Gets the index of this XML element among its parent's children. */ - int getElementPositionIndex() { xmlElements(this, _, _, result, _) } - - /** Gets the depth of this element within the XML file tree structure. */ - override int getDepth() { result = this.getParent().getDepth() + 1 } - - /** Gets an XML attribute of this XML element. */ - XmlAttribute getAnAttribute() { result.getElement() = this } - - /** Gets the attribute with the specified `name`, if any. */ - XmlAttribute getAttribute(string name) { result.getElement() = this and result.getName() = name } - - /** Holds if this XML element has an attribute with the specified `name`. */ - predicate hasAttribute(string name) { exists(this.getAttribute(name)) } - - /** Gets the value of the attribute with the specified `name`, if any. */ - string getAttributeValue(string name) { result = this.getAttribute(name).getValue() } - - /** Gets a printable representation of this XML element. */ - override string toString() { result = this.getName() } -} - -/** - * An attribute that occurs inside an XML element. - * - * Examples: - * - * ``` - * package="com.example.exampleapp" - * android:versionCode="1" - * ``` - */ -class XmlAttribute extends @xmlattribute, XmlLocatable { - /** Gets the name of this attribute. */ - string getName() { xmlAttrs(this, _, result, _, _, _) } - - /** Gets the XML element to which this attribute belongs. */ - XmlElement getElement() { xmlAttrs(this, result, _, _, _, _) } - - /** Holds if this attribute has a namespace. */ - predicate hasNamespace() { xmlHasNs(this, _, _) } - - /** Gets the namespace of this attribute, if any. */ - XmlNamespace getNamespace() { xmlHasNs(this, result, _) } - - /** Gets the value of this attribute. */ - string getValue() { xmlAttrs(this, _, _, result, _, _) } - - /** Gets a printable representation of this XML attribute. */ - override string toString() { result = this.getName() + "=" + this.getValue() } -} - -/** - * A namespace used in an XML file. - * - * Example: - * - * ``` - * xmlns:android="http://schemas.android.com/apk/res/android" - * ``` - */ -class XmlNamespace extends XmlLocatable, @xmlnamespace { - /** Gets the prefix of this namespace. */ - string getPrefix() { xmlNs(this, result, _, _) } - - /** Gets the URI of this namespace. */ - string getUri() { xmlNs(this, _, result, _) } - - /** Holds if this namespace has no prefix. */ - predicate isDefault() { this.getPrefix() = "" } - - override string toString() { - this.isDefault() and result = this.getUri() - or - not this.isDefault() and result = this.getPrefix() + ":" + this.getUri() - } -} - -/** - * A comment in an XML file. - * - * Example: - * - * ``` - * - * ``` - */ -class XmlComment extends @xmlcomment, XmlLocatable { - /** Gets the text content of this XML comment. */ - string getText() { xmlComments(this, result, _, _) } - - /** Gets the parent of this XML comment. */ - XmlParent getParent() { xmlComments(this, _, result, _) } - - /** Gets a printable representation of this XML comment. */ - override string toString() { result = this.getText() } -} - -/** - * A sequence of characters that occurs between opening and - * closing tags of an XML element, excluding other elements. - * - * Example: - * - * ``` - * This is a sequence of characters. - * ``` - */ -class XmlCharacters extends @xmlcharacters, XmlLocatable { - /** Gets the content of this character sequence. */ - string getCharacters() { xmlChars(this, result, _, _, _, _) } - - /** Gets the parent of this character sequence. */ - XmlParent getParent() { xmlChars(this, _, result, _, _, _) } - - /** Holds if this character sequence is CDATA. */ - predicate isCDATA() { xmlChars(this, _, _, _, 1, _) } - - /** Gets a printable representation of this XML character sequence. */ - override string toString() { result = this.getCharacters() } -} +import Make