From 6b86a911d09335a3b418a34fd2436ff1e20f65f3 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Sat, 1 May 2021 01:02:50 +0200 Subject: [PATCH] Java: Replace usage of toString() for Javadoc queries; add more Javadoc tags --- .../AvoidDeprecatedCallableAccess.ql | 2 +- .../Advisory/Documentation/JavadocCommon.qll | 23 ++++--- java/ql/src/semmle/code/java/Javadoc.qll | 61 +++++++++++++++---- .../InlineExpectationsTestPrivate.qll | 2 +- 4 files changed, 62 insertions(+), 26 deletions(-) diff --git a/java/ql/src/Advisory/Deprecated Code/AvoidDeprecatedCallableAccess.ql b/java/ql/src/Advisory/Deprecated Code/AvoidDeprecatedCallableAccess.ql index 354b82fe165db..8a2b9958f9120 100644 --- a/java/ql/src/Advisory/Deprecated Code/AvoidDeprecatedCallableAccess.ql +++ b/java/ql/src/Advisory/Deprecated Code/AvoidDeprecatedCallableAccess.ql @@ -15,7 +15,7 @@ import java private predicate isDeprecatedCallable(Callable c) { c.getAnAnnotation() instanceof DeprecatedAnnotation or - exists(c.getDoc().getJavadoc().getATag("@deprecated")) + exists(c.getDoc().getJavadoc().getATag().(DeprecatedTag)) } from Call ca, Callable c diff --git a/java/ql/src/Advisory/Documentation/JavadocCommon.qll b/java/ql/src/Advisory/Documentation/JavadocCommon.qll index 5c38e4e55ece0..056f0b4c0543a 100644 --- a/java/ql/src/Advisory/Documentation/JavadocCommon.qll +++ b/java/ql/src/Advisory/Documentation/JavadocCommon.qll @@ -5,10 +5,9 @@ import java /** Holds if the given `Javadoc` contains a minimum of a few characters of text. */ private predicate acceptableDocText(Javadoc j) { // Require minimum combined length of all non-tag elements. - sum(JavadocElement e, int toSum | - e = j.getAChild() and - not e = j.getATag(_) and - toSum = e.toString().length() + sum(JavadocText t, int toSum | + t = j.getATextElement() and + toSum = t.getText().length() | toSum ) >= 5 @@ -16,9 +15,9 @@ private predicate acceptableDocText(Javadoc j) { /** Holds if the given `JavadocTag` contains a minimum of a few characters of text. */ private predicate acceptableTag(JavadocTag t) { - sum(JavadocElement e, int toSum | - e = t.getAChild() and - toSum = e.toString().length() + sum(JavadocText text, int toSum | + text = t.getATextElement() and + toSum = text.getText().length() | toSum ) >= 5 @@ -72,7 +71,7 @@ class DocuParam extends Parameter { /** Holds if this parameter has a non-trivial `@param` tag. */ predicate hasAcceptableParamTag() { exists(ParamTag t | - t = this.getCallable().getDoc().getJavadoc().getATag("@param") and + t = this.getCallable().getDoc().getJavadoc().getATag() and t.getParamName() = this.getName() and acceptableTag(t) ) @@ -90,7 +89,7 @@ class DocuReturn extends DocuCallable { /** Holds if this callable's `Javadoc` has a non-trivial `@return` tag. */ predicate hasAcceptableReturnTag() { - acceptableTag(this.getDoc().getJavadoc().getATag("@return")) + acceptableTag(this.getDoc().getJavadoc().getATag().(ReturnTag)) } } @@ -111,9 +110,9 @@ class DocuThrows extends DocuCallable { predicate hasAcceptableThrowsTag(Exception e) { exists(Javadoc j | j = this.getDoc().getJavadoc() and - exists(JavadocTag t | - (t = j.getATag("@throws") or t = j.getATag("@exception")) and - t.getChild(0).toString() = e.getName() and + exists(ThrowsTag t | + t = j.getATag() and + t.getExceptionName() = e.getName() and acceptableTag(t) ) ) diff --git a/java/ql/src/semmle/code/java/Javadoc.qll b/java/ql/src/semmle/code/java/Javadoc.qll index 61d978fbd3578..f6cc568bd9eb3 100755 --- a/java/ql/src/semmle/code/java/Javadoc.qll +++ b/java/ql/src/semmle/code/java/Javadoc.qll @@ -16,8 +16,19 @@ class JavadocParent extends @javadocParent, Top { /** Gets the number of documentation elements attached to this parent. */ int getNumChild() { result = count(getAChild()) } - /** Gets a documentation element with the specified Javadoc tag name. */ - JavadocTag getATag(string name) { result = this.getAChild() and result.getTagName() = name } + /** + * DEPRECATED: Only `Javadoc` can have tag elements; `JavadocTag` (which also extends + * `JavadocParent`) cannot have nested tag elements. Therefore this predicate has been + * moved to `Javadoc`. + * + * Gets a documentation element with the specified Javadoc tag name. + */ + deprecated JavadocTag getATag(string name) { + result = this.getAChild() and result.getTagName() = name + } + + /** Gets a text documentation element which is a direct child of this. */ + JavadocText getATextElement() { result = this.getAChild() } /*abstract*/ override string toString() { result = "Javadoc" } } @@ -27,11 +38,19 @@ class Javadoc extends JavadocParent, @javadoc { /** Gets the number of lines in this Javadoc comment. */ int getNumberOfLines() { result = this.getLocation().getNumberOfCommentLines() } + /** Gets a documentation element with the specified Javadoc tag name. */ + override JavadocTag getATag(string name) { + result = this.getATag() and result.getTagName() = name + } + + /** Gets a Javadoc tag documentation element. */ + JavadocTag getATag() { result = getAChild() } + /** Gets the value of the `@version` tag, if any. */ - string getVersion() { result = this.getATag("@version").getChild(0).toString() } + string getVersion() { result = getATag().(VersionTag).getVersion() } /** Gets the value of the `@author` tag, if any. */ - string getAuthor() { result = this.getATag("@author").getChild(0).toString() } + string getAuthor() { result = getATag().(AuthorTag).getAuthorName() } override string toString() { result = toStringPrefix() + getChild(0) + toStringPostfix() } @@ -90,7 +109,7 @@ class JavadocTag extends JavadocElement, JavadocParent, @javadocTag { override string toString() { result = this.getTagName() } /** Gets the text associated with this Javadoc tag. */ - override string getText() { result = this.getChild(0).toString() } + override string getText() { result = this.getChild(0).(JavadocText).getText() } override string getAPrimaryQlClass() { result = "JavadocTag" } } @@ -100,21 +119,26 @@ class ParamTag extends JavadocTag { ParamTag() { this.getTagName() = "@param" } /** Gets the name of the parameter. */ - string getParamName() { result = this.getChild(0).toString() } + string getParamName() { result = this.getChild(0).(JavadocText).getText() } /** Gets the documentation for the parameter. */ - override string getText() { result = this.getChild(1).toString() } + override string getText() { result = this.getChild(1).(JavadocText).getText() } +} + +/** A Javadoc `@return` tag. */ +class ReturnTag extends JavadocTag { + ReturnTag() { this.getTagName() = "@return" } } /** A Javadoc `@throws` or `@exception` tag. */ class ThrowsTag extends JavadocTag { - ThrowsTag() { this.getTagName() = "@throws" or this.getTagName() = "@exception" } + ThrowsTag() { this.getTagName() = ["@throws", "@exception"] } /** Gets the name of the exception. */ - string getExceptionName() { result = this.getChild(0).toString() } + string getExceptionName() { result = this.getChild(0).(JavadocText).getText() } /** Gets the documentation for the exception. */ - override string getText() { result = this.getChild(1).toString() } + override string getText() { result = this.getChild(1).(JavadocText).getText() } } /** A Javadoc `@see` tag. */ @@ -122,7 +146,12 @@ class SeeTag extends JavadocTag { SeeTag() { getTagName() = "@see" } /** Gets the name of the entity referred to. */ - string getReference() { result = getChild(0).toString() } + string getReference() { result = getText() } +} + +/** A Javadoc `@deprecated` tag. */ +class DeprecatedTag extends JavadocTag { + DeprecatedTag() { this.getTagName() = "@deprecated" } } /** A Javadoc `@author` tag. */ @@ -130,7 +159,15 @@ class AuthorTag extends JavadocTag { AuthorTag() { this.getTagName() = "@author" } /** Gets the name of the author. */ - string getAuthorName() { result = this.getChild(0).toString() } + string getAuthorName() { result = getText() } +} + +/** A Javadoc `@version` tag. */ +class VersionTag extends JavadocTag { + VersionTag() { this.getTagName() = "@version" } + + /** Gets the version specified by this tag. */ + string getVersion() { result = getText() } } /** A piece of Javadoc text. */ diff --git a/java/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll b/java/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll index e2c0e0091baf7..788a98116b705 100644 --- a/java/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll +++ b/java/ql/test/TestUtilities/InlineExpectationsTestPrivate.qll @@ -8,5 +8,5 @@ class LineComment extends Javadoc { LineComment() { isEolComment(this) } /** Gets the contents of the given comment, _without_ the preceding comment marker (`//`). */ - string getContents() { result = this.getChild(0).toString() } + string getContents() { result = this.getChild(0).(JavadocText).getText() } }