Skip to content

fix qhelp files #19707

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

LWSimpkins
Copy link
Contributor

Several qhelp files have errors when running the codeql generate query-help --format=markdown <qhelp-file command

  • Nested code inside <ul>, such as a second <ul> or a <p>
    • This may be valid HTML, but is not supported by the qhelp file/throws an error when running the generate query-help command

@Copilot Copilot AI review requested due to automatic review settings June 9, 2025 22:40
@LWSimpkins LWSimpkins requested review from a team as code owners June 9, 2025 22:40
Copy link
Contributor

github-actions bot commented Jun 9, 2025

QHelp previews:

cpp/ql/src/Metrics/Classes/CNumberOfFunctions.qhelp

Number of functions per class

This metric measures the number of functions in classes below this location in the tree. At a class level, it just measures the number of functions in the class itself.

A class with too many functions is generally trying to do too much, either at the interface or implementation level or both. It can be difficult for readers to understand because there is a confusing list of operations. Such classes often lack cohesion and are prime candidates for refactoring.

Recommendation

Classes have too many functions for a variety of reasons, and the appropriate fix is different in each case:

  • The class may be too large in general, and taking on more responsibilities than it should (see [Martin] for more on responsibilities). In this case, the solution is to identify each of the different responsibilities the class is taking on, and split it into multiple classes, e.g. using the 'Extract Class' refactoring from [Fowler].
  • There may be lots of duplication within the class itself, i.e. some of the functions may be doing overlapping things. In this case, the solution is to redesign the class so that each new function has a single, unique responsibility.
  • The class may be quite small at the implementation level, but trying to provide its user with a wide range of 'utility' functions that don't actually need to be part of the class. (A classic example of this is the std::string class in the C++ Standard Library.) As [Sutter] observes, there are at least two key problems with this approach: 1. It may be possible to generalize some of the utility functions beyond the narrow context of the class in question -- by bundling them with the class, the class author reduces the scope for functionality reuse. 2. It's usually impossible for the class author to know every possible operation that the user might want to perform on the class, so the public interface will inherently be incomplete. New utility functions will end up having a different syntax to the privileged public functions in the class, negatively impacting on code consistency. To refactor a class like this, simply move its utility functions elsewhere, paring its public interface down to the bare minimum.
  • The class may be a base class in a badly-designed inheritance hierarchy. Such classes have many public functions in order to support features that are only used by one or two of their descendants. In this situation, the solution is to redesign the hierarchy, possibly by refactoring it into a component-based architecture (see [Microsoft Patterns & Practices Team]).

References

cpp/ql/src/Metrics/Classes/CSizeOfAPI.qhelp

Size of API per class

This metric measures the number of public functions for each public class.

A class with too many public functions is generally trying to do too much, either at the interface or implementation level or both. It can be difficult for readers to understand because there is a confusing list of operations. Such classes often lack cohesion and are prime candidates for refactoring.

Recommendation

Classes have wide interfaces for a variety of different reasons, and the appropriate fix is different in each case:

  • The class may be too large in general, and taking on more responsibilities than it should (see [Martin] for more on responsibilities). In this case, the solution is to identify each of the different responsibilities the class is taking on, and split it into multiple classes, e.g. using the 'Extract Class' refactoring from [Fowler].
  • There may be lots of duplication within the class itself, that is, the actions of some of the public functions may overlap. In this case, the solution is to redesign the interface so that each new public function has a single, unique responsibility.
  • The class may be quite small at the implementation level, but trying to provide its user with a wide range of 'utility' functions that don't actually need to be part of the class. (A classic example of this is the std::string class in the C++ Standard Library.) As [Sutter] observes, there are at least two key problems with this approach: * 1. It may be possible to generalize some of the utility functions beyond the narrow context of the class in question -- by bundling them with the class, the class author reduces the scope for functionality reuse. 2. It's usually impossible for the class author to know every possible operation that the user might want to perform on the class, so the public interface will inherently be incomplete. New utility functions will end up having a different syntax to the privileged public functions in the class, negatively impacting on code consistency.* To refactor a class like this, simply move its utility functions elsewhere, paring its public interface down to the bare minimum.
  • The class may be a base class in a badly-designed inheritance hierarchy. Such classes have many public functions to support features that are only used by one or two of their descendants. In this situation, the solution is to redesign the hierarchy, possibly by refactoring it into a component-based architecture.

References

java/ql/src/Metrics/RefTypes/TInheritanceDepth.qhelp

Type inheritance depth

This metric measures the inheritance depth of a reference type (e.g. a class).

Whilst inheritance provides an avenue for code reuse, overly-deep class hierarchies can become a maintenance headache. Classes that inherit from many other classes can be brittle and hard to understand, because they depend on all of the classes further up the hierarchy. Conversely, changes to classes nearer the root of the hierarchy become harder and harder to make without breaking the descendants. In extreme cases, where the design of the hierarchy is seriously inappropriate, the class at the top of the hierarchy can become a 'blob' class: a storage point for anything that might be needed by one of its descendants. This is a key indicator that some serious refactoring is needed.

Recommendation

As with many metrics, a high inheritance depth should be seen as an indicator that something is amiss, but further investigation will be needed to clarify the cause of the problem. Here are two possibilities:

  1. A class and its superclass represent fundamentally the same abstraction. In this case, they should generally be merged together (see the 'Collapse Hierarchy' refactoring on pp.279-80 of [Fowler]). For example, suppose that in the following class hierarchy both A and C represent fundamentally the same thing, then they should be merged together as shown:
Before After
2. The class hierarchy is trying to represent variation in more than one dimension using single inheritance. This can lead to an unnecessarily deep class hierarchy with lots of code duplication. For example, consider the following:

BeforeIn languages that support it (such as C++), this situation could be modeled somewhat more effectively using multiple inheritance, but an altogether better approach is to use a component-based architecture (i.e. composition):

AfterUsing this method, each of the leaf classes in the above would be represented as the composition of a type, fuel and style component, e.g. a ColoredPetrolVan would have a Van type component, a Petrol fuel component and a Colored style component. Note how this effectively reduces both the height of the class hierarchy and the amount of code duplication that will be necessary.

For readers who are interested in this sort of approach, a good reference is [West].

References

java/ql/src/Metrics/RefTypes/TNumberOfCallables.qhelp

Number of methods

This metric measures the number of methods in reference types below this location in the tree. At a type level, it just measures the number of methods in the type itself.

A class with too many methods is generally trying to do too much, either at the interface or implementation level or both. It is common for the set of operations such a class provides to be diverse and wide-ranging, making it difficult for readers to understand. Such classes often lack cohesion and are prime candidates for refactoring.

Recommendation

Classes have too many methods for a variety of reasons, and the appropriate fix is different in each case:

  • The class may be too large in general, and taking on more responsibilities than it should (see [Martin] for more on responsibilities). In this case, the solution is to identify each of the different responsibilities the class is taking on, and split it into multiple classes, e.g. using the 'Extract Class' refactoring from [Fowler].
  • There may be lots of duplication within the class itself, i.e. some of the methods may be doing overlapping things. In this case, the solution is to redesign the class so that each new method has a single, unique responsibility.
  • The class may be quite small at the implementation level, but trying to provide its user with a wide range of 'utility' methods that don't actually need to be part of the class. (A classic example of this is the std::string class in the C++ Standard Library.) As [Sutter] observes, there are at least two key problems with this approach: * 1. It may be possible to generalize some of the utility methods beyond the narrow context of the class in question -- by bundling them with the class, the class author reduces the scope for functionality reuse. 2. It's usually impossible for the class author to know every possible operation that the user might want to perform on the class, so the public interface will inherently be incomplete. New utility methods will end up having a different syntax to the privileged public methods in the class, negatively impacting on code consistency.* To refactor a class like this, simply move its utility methods elsewhere, paring its public interface down to the bare minimum.
  • The class may be a base class in a badly-designed inheritance hierarchy. Such classes have many public methods in order to support features that are only used by one or two of their descendants. In this situation, the solution is to redesign the hierarchy, possibly by refactoring it into a component-based architecture (see [Microsoft Patterns & Practices Team]).

References

  • M. Fowler. Refactoring pp. 65, 122-5. Addison-Wesley, 1999.
  • R. Martin. Agile Software Development: Principles, Patterns, and Practices Chapter 8 - SRP: The Single-Responsibility Principle. Pearson Education, 2003.
  • H. Sutter. GotW #84: Monoliths "Unstrung". Published online, 2002.
  • Microsoft Patterns & Practices Team. Architectural Patterns and Styles Microsoft Application Architecture Guide, 2nd Edition. Microsoft Press, 2009.
java/ql/src/Metrics/RefTypes/TNumberOfFields.qhelp

Number of fields

A class that contains a high number of fields may indicate the following problems:

  • The class may be too big or have too many responsibilities.
  • Several of the fields may be part of the same abstraction.

Recommendation

The solution depends on the reason for the high number of fields:

  • If the class is too big, you should split it into multiple smaller classes.
  • If several of the fields are part of the same abstraction, you should group them into a separate class, using the 'Extract Class' refactoring described in [Fowler].

Example

In the following example, class Person contains a number of fields.

class Person {
    private String m_firstName;
    private String m_LastName;
    private int m_houseNumber;
    private String m_street;
    private String m_settlement;
    private Country m_country;
    private Postcode m_postcode;
    // ...
}

This can be refactored by grouping fields that are part of the same abstraction into new classes Name and Address.

class Name {
    private String m_firstName;
    private String m_lastName;
    // ...
}

class Address {
    private int m_houseNumber;
    private String m_street;
    private String m_settlement;
    private Country m_country;
    private Postcode m_postcode;
    // ...
}

class Person {
    private Name m_name;
    private Address m_address;
    // ...
}

References

  • M. Fowler, Refactoring. Addison-Wesley, 1999.
java/ql/src/Metrics/RefTypes/TSizeOfAPI.qhelp

Size of a type's API

This metric measures the number of public methods for each public class.

A class with too many public methods is generally trying to do too much, either at the interface or implementation level or both. It can be difficult for readers to understand because there is a confusing list of operations. Such classes often lack cohesion and are prime candidates for refactoring.

Recommendation

Classes have wide interfaces for a variety of different reasons, and the appropriate fix is different in each case:

  • The class may be too large in general, and taking on more responsibilities than it should (see [Martin] for more on responsibilities). In this case, the solution is to identify each of the different responsibilities the class is taking on, and split it into multiple classes, e.g. using the 'Extract Class' refactoring from [Fowler].
  • There may be lots of duplication within the class itself, i.e. some of the public methods may be doing overlapping things. In this case, the solution is to redesign the interface so that each new public method has a single, unique responsibility.
  • The class may be quite small at the implementation level, but trying to provide its user with a wide range of 'utility' methods that don't actually need to be part of the class. (A classic example of this is the std::string class in the C++ Standard Library.) As [Sutter] observes, there are at least two key problems with this approach: * 1. It may be possible to generalize some of the utility methods beyond the narrow context of the class in question -- by bundling them with the class, the class author reduces the scope for functionality reuse. 2. It's usually impossible for the class author to know every possible operation that the user might want to perform on the class, so the public interface will inherently be incomplete. New utility methods will end up having a different syntax to the privileged public methods in the class, negatively impacting on code consistency.* To refactor a class like this, simply move its utility methods elsewhere, paring its public interface down to the bare minimum.
  • The class may be a base class in a badly-designed inheritance hierarchy. Such classes have many public methods in order to support features that are only used by one or two of their descendants. In this situation, the solution is to redesign the hierarchy, possibly by refactoring it into a component-based architecture.

References

  • M. Fowler. Refactoring pp. 65, 122-5. Addison-Wesley, 1999.
  • R. Martin. Agile Software Development: Principles, Patterns, and Practices Chapter 8 - SRP: The Single-Responsibility Principle. Pearson Education, 2003.
  • H. Sutter. GotW #84: Monoliths "Unstrung". Published online, 2002.

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes errors in multiple .qhelp files by removing unsupported nested HTML (<ul>, <li>, <p>) and replacing them with inline numbered formatting that the codeql generate query-help command can handle.

  • Replace nested lists with inline numbered items wrapped in HTML tags
  • Remove unsupported <p> elements within list items
  • Align formatting across Java and C++ metric qhelp files

Reviewed Changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
java/ql/src/Metrics/RefTypes/TSizeOfAPI.qhelp Replaced <ul>/<li> block with <i>-wrapped numbered list
java/ql/src/Metrics/RefTypes/TNumberOfFields.qhelp Removed nested <p> around list item
java/ql/src/Metrics/RefTypes/TNumberOfCallables.qhelp Replaced <ul>/<li> block with <i>-wrapped numbered list
java/ql/src/Metrics/RefTypes/TInheritanceDepth.qhelp Converted <ul>/<li> to <p>-wrapped numbered paragraphs
cpp/ql/src/Metrics/Classes/CSizeOfAPI.qhelp Replaced <ul>/<li> block with <i>-wrapped numbered list
cpp/ql/src/Metrics/Classes/CNumberOfFunctions.qhelp Replaced <ul>/<li> block with <i>-wrapped numbered list
Comments suppressed due to low confidence (1)

java/ql/src/Metrics/RefTypes/TInheritanceDepth.qhelp:31

  • [nitpick] Inconsistent HTML formatting: this file uses

    tags for numbered items while others use . Consider standardizing the approach across all qhelp files for consistency.

<p>1. A class and its superclass represent fundamentally the same abstraction.

Comment on lines +49 to +59
<i>
1. It may be possible to generalize some of the utility methods beyond the
narrow context of the class in question -- by bundling them with the class,
the class author reduces the scope for functionality reuse.
</li>

<li>
It's usually impossible for the class author to know every possible
2. It's usually impossible for the class author to know every possible
operation that the user might want to perform on the class, so the public
interface will inherently be incomplete. New utility methods will end up
having a different syntax to the privileged public methods in the class,
negatively impacting on code consistency.
</li>
</ul>
</i>
Copy link
Preview

Copilot AI Jun 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Using tags to represent block-level numbered lists can be semantically confusing. Consider using plain markdown numbered lists (e.g., '1. ...\n2. ...') instead of HTML to improve clarity and compatibility.

Copilot uses AI. Check for mistakes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant