Blog 4 min read

Tracking C++ Code Smells: A Database Approach

Share this article
Tracking C++ Code Smells: A Database Approach

Static analysis is not only about directly finding bugs, but also about finding bug-prone situations that can hurt code readability and maintainability. Static analysis can examine many other properties of the code:

  • Code metrics: for example, methods with too many loops, if, else, switch and case statements end up being hard to understand, hence hard to maintain. Counting these through the code metric Cyclomatic Complexity is a great way to assess when a method becomes too complex.
  • Dependencies: if the classes of your program are entangled, the effects of any changes in the code become unpredictable. Static analysis can help to assess when classes and components are entangled.
  • Immutability: types that are used concurrently by several threads should be immutable; otherwise you’ll have to protect state read/write access with complex lock strategies that will end up being unmaintainable. Static analysis can make sure that some classes remain immutable.
  • Dead code: dead code is code that can be removed safely, because it is not invoked anymore at runtime. Not only can it be removed, but it must be removed, because this extra code adds unnecessary complexity to the program. Static analysis can find most of the dead code in your program (yet not all).
  • API breaking change: if you present an API to your client, it is very easy to remove a public member without noticing and thus break your clients’ code. Static analysis can compare two states of a program and warn about this pitfall.
  • API usage: some APIs are intended to be used carefully. For example, a class that holds disposable fields must generally be disposable itself, except when the disposable field’s lifetime is not aligned with the class instance’s lifetime — which then smells like a design problem.

A code smell can also be considered a bug-prone situation. Here is its definition from Wikipedia:

In computer programming, code smell, (or bad smell) is any symptom in the source code of a program that possibly indicates a deeper problem. According to Martin Fowler, "a code smell is a surface indication that usually corresponds to a deeper problem in the system". Another way to look at smells is with respect to principles and quality: "smells are certain structures in the code that indicate violation of fundamental design principles and negatively impact design quality". Code smells are usually not bugs—they are not technically incorrect and do not currently prevent the program from functioning. Instead, they indicate weaknesses in design that may be slowing down development or increasing the risk of bugs or failures in the future. Bad code smells can be an indicator of factors that contribute to technical debt. Robert C. Martin calls a list of code smells a "value system" for software craftsmanship.

Many useful tools can detect bugs in a C++ codebase, including Cppcheck, Clang-Tidy, and the Visual Studio analyzer. But what about detecting code smells?

While static analysis tool creators can decide which situations are considered bugs, code smells are more subjective and depend on the development team’s choices. For example, one team could consider that a method with more than 20 lines is complex, while another team could set the maximum at 30. If a tool detects code smells, it must also allow teams to customize the relevant rules and thresholds.

Code as Data Is the Best Way to Detect Code Smells

Static analysis is the idea of analyzing source code for various properties and reporting on those properties, but it’s also, philosophically, the idea of treating code as data. This can feel unusual to application developers because we are used to thinking of source code as instructions, procedures, and algorithms. But treating code as data is also extremely powerful.

After analyzing a source file, we can extract its AST and generate a model containing a wealth of useful information about the code. We can then query this model using a code query language similar to SQL.

CppDepend provides a code query language named CQLinq to query the code base like a database. Developers, designers and architects can define their own queries to easily find code smells.

With CQLinq, we can combine data from code metrics, dependencies, API usage, and other model information to define advanced queries that identify specific code smells.

Here’s an example of a CQLinq query that matches the most complex methods:

bugs

Summary

It is often better to combine several C++ tools to detect problems in your codebase: some tools focus on bugs, while others can also detect code smells. CppDepend brings these approaches together by providing an easy way to define custom queries and by importing results from other static analysis tools so they can also be queried with CQLinq.

Share this article