Learn more about Non-Final Class Information & Warnings

This post explains details about using the non-final class information in Swiftalyzer. It helps us to identify classes that can be final but are missing the final keyword.

After learning about the final keyword, we’re seeing how we can find non-final classes with Swiftalyzer. Finally, we’re going to configure warnings, so that we can find areas of improvement in our app at first glance.

Getting an Overview of Non-Final Classes with Swiftalyzer

Classes that have the final keyword added to their declaration can not be subclassed. This has some benefits:

  • Preventing unintended side-effects when changing a seemingly unrelated class: No inheriting class can override methods or properties to change the behavior.
  • Performance benefits: By restricting the possibility of overrides, the compiler can make certain assumptions about the code. This can result in faster execution.

When all classes without subclasses are final, it’s easy to see if a class is part of a inheritance hierarchy. Looking at its declaration gives us all information without needing to search the project for potential subclasses. However, this requires the team to be consistent with the usage of final.

But how can we find out if a class could be final? We could add the keyword to a class and build the app. If it compiles, the class can be final, otherwise there’ll be errors. Unfortunately, this manual progress quickly becomes time consuming.

Swiftalyzer automatically analyses the declarations of the classes in our app and knows, which ones don’t have the final keyword. It also sees all inheritances and thus knows, which classes can not be final because of subclasses. That’s why Swiftalyzer can give us a list of classes that can be final but are missing the final keyword. Let’s see how this looks like for a concrete example.

We’ll use a demo project analysis. Download the analysis file and open it in Swiftalyzer to explore the analysis: DemoProject

The analysed project contains 5 classes:

final class FinalClass { }

class NonFinalClass { }

class NonFinalSuperClass { }

final class FinalSubClass: NonFinalSuperClass { }

class NonFinalSubClass: NonFinalSuperClass { }

This is how Swiftalyzer visualises the dependency graph:

A graph showing the files and entities of the demo project. Arrows between entities show dependencies between them.
Dependency graph of the demo project.

We can get a list of non-final classes when selecting the third tab in the right panel, which is highlighted in the image. This tab shows general project information independent from the currently selected node.

A screenshot of Swiftalyzer with the 4 tabs of the information panel. The third one is selected. A red border highlights the third tab.
The third tab shows general information about the project.

Among other things, we can find a list of classes here, which could be final but are missing the final keyword.

In this example these are the classes NonFinalClass and NonFinalSubClass. These two don’t have the final keyword and there are no classes inheriting from them.

NonFinalSuperClass is also missing the final keyword. But since there are subclasses, making it final would lead to compilation errors.

A screenshot from Swiftalyzer showing a list of class names that are not final but no other class inherits from them. The list names the classes NonFinalClass and NonFinalSubClass.
A list of class names makes it easy to find non-final classes.

In case we want to accept that a class is non-final without seeing warnings about it, or if the warning is a false positive, we can ignore the finding.

To do so, we open a context menu via a right click on the dark grey box. This context menu has an item to ignore finding. The next picture shows how this looks like when the finding for the class NonFinalClass is ignored.

A finding can be un-ignored again by opening the context menu again and clicking on the item to un-ignore it.

A similar screenshot to the one before from Swiftalyzer showing a list of class names that are not final but no other class inherits from them. The list names the classes NonFinalClass and NonFinalSubClass. The class NonFinalClass is ignored and shown with a slightly different color at the bottom of the list.
An ignored item looks different then an un-ignored item and is placed at the bottom of the list.

Finding Non-Final Classes with Warnings

Warnings are a great way of quickly finding areas of improvement in our apps. A class with a warning has a red bubble in the upper right corner of the node that shows the number of warnings.

We can configure warnings in the configuration tab. It’s the fourth tab in the right panel, which is highlighted in the image. Select it to see options for various warnings, like the warning about non-final classes below.

A screenshot of Swiftalyzer with the 4 tabs of the information panel. The last one is selected. A red border highlights the fourth tab.
Configure warnings in the fourth tab of the right panel.

There’s a checkbox to enable or disable the warning. It’s selected by default meaning that Swiftalyzer shows a warning next to each class node that could be final but is missing the final keyword. Unselecting this checkbox removes all warnings about non-final classes in the dependency graph.

A checkbox allows to enable or disable warnings about non-final classes in the dependency graph. The checkbox is enabled.
Enabling or disabling warnings via the checkbox.

With the non-final class warning enabled, we see indicators at the same classes as we’ve seen in the list before:

A similar graph as above showing the files and entities of the demo project. Arrows between entities show dependencies between them. In addition, the nodes representing the classes NonFinalClass and NonFinalSubClass have red bubbles in the top right corner with the number 1. This means that there is one warning for each of these classes.
The graph shows a warning for classes that are not final and are not subclassed.