From a0703717966ddd7c4b1c40e18a845a95082f5b69 Mon Sep 17 00:00:00 2001 From: Nicolas Will Date: Sat, 13 Jul 2024 14:53:12 +0200 Subject: [PATCH 1/3] Support Doxygen block comments --- .../A2-7-3/UndocumentedUserDefinedType.ql | 40 ++++++++++++++++++- .../UndocumentedUserDefinedType.expected | 20 +++++----- cpp/autosar/test/rules/A2-7-3/test.cpp | 20 ++++++++++ 3 files changed, 69 insertions(+), 11 deletions(-) diff --git a/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql b/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql index a8bfe3b361..5f8f68d50f 100644 --- a/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql +++ b/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql @@ -25,6 +25,38 @@ private predicate isInFunctionScope(Declaration d) { isInFunctionScope(d.getDeclaringType()) } +private string doxygenCommentGroupStrings(boolean opening) { + opening = true and result = ["///@{", "/**@{*/"] + or + opening = false and result = ["///@}", "/**@}*/"] +} + +private predicate isBetweenDoxygenCommentGroup( + Location loc, Comment opening, Comment body, Comment closing +) { + // All in the same file + loc.getFile() = opening.getLocation().getFile() and + loc.getFile() = closing.getLocation().getFile() and + loc.getFile() = body.getLocation().getFile() and + // The comments are doxygen comments + opening.getContents().matches(doxygenCommentGroupStrings(true)) and + closing.getContents().matches(doxygenCommentGroupStrings(false)) and + // The closing comment is after the opening comment + opening.getLocation().getStartLine() < closing.getLocation().getStartLine() and + // The `body` comment directly precedes the opening comment + body.getLocation().getEndLine() = opening.getLocation().getStartLine() - 1 and + // There are no other opening/closing comment pairs between the opening and closing comments + not exists(Comment c | + c.getContents().matches(doxygenCommentGroupStrings(_)) and + c.getLocation().getStartLine() > opening.getLocation().getStartLine() and + c.getLocation().getStartLine() < closing.getLocation().getStartLine() + ) and + // `loc` is between the opening and closing comments and after the body comment + loc.getStartLine() > opening.getLocation().getStartLine() and + loc.getStartLine() < closing.getLocation().getStartLine() and + loc.getStartLine() > body.getLocation().getEndLine() +} + /** * A declaration which is required to be preceded by documentation by AUTOSAR A2-7-3. */ @@ -80,11 +112,12 @@ class DocumentableDeclaration extends Declaration { } /** - * A `DeclarationEntry` is considered documented if it has an associated `Comment`, and the `Comment` - * precedes the `DeclarationEntry`. + * A `DeclarationEntry` is considered documented if it has an associated `Comment`, the `Comment` + * precedes the `DeclarationEntry`, and the `Comment` is not a doxygen comment group prefix. */ predicate isDocumented(DeclarationEntry de) { exists(Comment c | c.getCommentedElement() = de | + not c.getContents() = doxygenCommentGroupStrings(true) and exists(Location commentLoc, Location deLoc | commentLoc = c.getLocation() and deLoc = de.getLocation() | @@ -96,6 +129,9 @@ predicate isDocumented(DeclarationEntry de) { commentLoc.getStartColumn() < deLoc.getStartColumn() ) ) + or + // The declaration entry is between a doxygen comment group + isBetweenDoxygenCommentGroup(de.getLocation(), _, _, _) } from DocumentableDeclaration d, DeclarationEntry de diff --git a/cpp/autosar/test/rules/A2-7-3/UndocumentedUserDefinedType.expected b/cpp/autosar/test/rules/A2-7-3/UndocumentedUserDefinedType.expected index 0ae42152f7..43a8773361 100644 --- a/cpp/autosar/test/rules/A2-7-3/UndocumentedUserDefinedType.expected +++ b/cpp/autosar/test/rules/A2-7-3/UndocumentedUserDefinedType.expected @@ -1,9 +1,11 @@ -| test.cpp:70:7:70:12 | definition of ClassD | Declaration entry for user-defined type ClassD is missing documentation. | -| test.cpp:72:7:72:7 | definition of a | Declaration entry for member variable a is missing documentation. | -| test.cpp:73:14:73:14 | declaration of b | Declaration entry for member variable b is missing documentation. | -| test.cpp:74:8:74:8 | declaration of f | Declaration entry for function f is missing documentation. | -| test.cpp:76:7:76:7 | definition of c | Declaration entry for member variable c is missing documentation. | -| test.cpp:78:6:78:6 | declaration of d | Declaration entry for function d is missing documentation. | -| test.cpp:81:6:81:6 | definition of e | Declaration entry for function e is missing documentation. | -| test.cpp:88:1:88:30 | definition of message_to_string_undocumented | Declaration entry for function message_to_string_undocumented is missing documentation. | -| test.cpp:160:21:160:24 | definition of kBar | Declaration entry for member variable kBar is missing documentation. | +| test.cpp:74:8:74:8 | declaration of j | Declaration entry for function j is missing documentation. | +| test.cpp:75:8:75:8 | declaration of k | Declaration entry for function k is missing documentation. | +| test.cpp:90:7:90:12 | definition of ClassD | Declaration entry for user-defined type ClassD is missing documentation. | +| test.cpp:92:7:92:7 | definition of a | Declaration entry for member variable a is missing documentation. | +| test.cpp:93:14:93:14 | declaration of b | Declaration entry for member variable b is missing documentation. | +| test.cpp:94:8:94:8 | declaration of f | Declaration entry for function f is missing documentation. | +| test.cpp:96:7:96:7 | definition of c | Declaration entry for member variable c is missing documentation. | +| test.cpp:98:6:98:6 | declaration of d | Declaration entry for function d is missing documentation. | +| test.cpp:101:6:101:6 | definition of e | Declaration entry for function e is missing documentation. | +| test.cpp:108:1:108:30 | definition of message_to_string_undocumented | Declaration entry for function message_to_string_undocumented is missing documentation. | +| test.cpp:180:21:180:24 | definition of kBar | Declaration entry for member variable kBar is missing documentation. | diff --git a/cpp/autosar/test/rules/A2-7-3/test.cpp b/cpp/autosar/test/rules/A2-7-3/test.cpp index 8e9e180458..43b75b604a 100644 --- a/cpp/autosar/test/rules/A2-7-3/test.cpp +++ b/cpp/autosar/test/rules/A2-7-3/test.cpp @@ -60,10 +60,30 @@ class ClassC { // COMPLIANT /// @param i an integer. /// @throw std::runtime_error void f(int i); // COMPLIANT + + /** Same documentation for all members + * This is a multiline comment. + */ + ///@{ + void g(); // COMPLIANT + void h(); // COMPLIANT + void i(); // COMPLIANT + ///@} + + ///@{ + void j(); // NON_COMPLIANT + void k(); // NON_COMPLIANT + /** Member-specific documentation */ + void l(); // COMPLIANT + ///@} + private: /// @brief A Doxygen comment. int c; // COMPLIANT }; +void ClassC::i() { // not flagged, as we will only flag the non-definition + // declaration +} /// A Doxygen comment. void c(); // COMPLIANT From 9f5b134da817e8926ea29068c6d695b78958d4fe Mon Sep 17 00:00:00 2001 From: Nicolas Will Date: Sat, 13 Jul 2024 14:56:23 +0200 Subject: [PATCH 2/3] Create 2024-07-12-support-doxygen-comment-groups.md --- change_notes/2024-07-12-support-doxygen-comment-groups.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 change_notes/2024-07-12-support-doxygen-comment-groups.md diff --git a/change_notes/2024-07-12-support-doxygen-comment-groups.md b/change_notes/2024-07-12-support-doxygen-comment-groups.md new file mode 100644 index 0000000000..b0d7a148ba --- /dev/null +++ b/change_notes/2024-07-12-support-doxygen-comment-groups.md @@ -0,0 +1,2 @@ +- `A2-7-3` - `UndocumentedUserDefinedType.ql`: + - Fixes #391. Declarations for which a Doxygen comment group provides documentation will no longer produce results. \ No newline at end of file From fb5c4bce02593bdd380bcd132c9e5a53c34a6e2d Mon Sep 17 00:00:00 2001 From: Nicolas Will Date: Sat, 13 Jul 2024 16:23:13 +0200 Subject: [PATCH 3/3] Fix A2-7-3 performance issue Caches `isDocumented` and `isBetweenDoxygenCommentGroup` --- cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql b/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql index 5f8f68d50f..c3295275db 100644 --- a/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql +++ b/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql @@ -31,6 +31,7 @@ private string doxygenCommentGroupStrings(boolean opening) { opening = false and result = ["///@}", "/**@}*/"] } +pragma[inline] private predicate isBetweenDoxygenCommentGroup( Location loc, Comment opening, Comment body, Comment closing ) { @@ -115,6 +116,7 @@ class DocumentableDeclaration extends Declaration { * A `DeclarationEntry` is considered documented if it has an associated `Comment`, the `Comment` * precedes the `DeclarationEntry`, and the `Comment` is not a doxygen comment group prefix. */ +cached predicate isDocumented(DeclarationEntry de) { exists(Comment c | c.getCommentedElement() = de | not c.getContents() = doxygenCommentGroupStrings(true) and