Post

Code Statistics and Analysis Tools

CLOC code statistics tool, oclint static analysis tool

Code Statistics and Analysis Tools

Here are two tools:

For third-party tool installation, I recommend using Homebrew. Tang Qiao also recommended it in his blog. Use brew search xxxx to check whether the tool can be installed through Homebrew.

CLOC

CLOC is a command-line tool specifically for code statistics and supports almost all languages.

Install with Homebrew: brew install cloc. It is also very easy to use. In the terminal, go to the project directory and run cloc ./, which will count all code under the directory. If you do not want to include certain folders, you can specify directories to ignore, for example to ignore the Pods folder: cloc ./ --exclude-dir=Pods.

Statistics result: image

OCLint

OCLint is a very powerful static code analysis tool, and it was created by Chinese developers.

To make things easier in the long run, first install xctool: brew install xctool, which is Facebook’s replacement for Apple’s xcodebuild.

Install OCLint: brew install Caskroom/cask/oclint. To make the analysis results display directly in Xcode, you also need to complete the following steps:

  1. Add an Aggregate target, image image
  2. Add a Run Script to the Aggregate you just created. Note: do not click the Editor menu while the Aggregate is selected, otherwise the Add Run Script Build Phase button will be grayed out. image
  3. Add the script code. The script code is slightly different from the one in the official documentation.
#import path
export PATH=${PATH}:/usr/local/bin
#import what we have in bash_profile
source ~/.bash_profile
#check for oclint
hash oclint &> /dev/null
if [ $? -eq 1 ]; then
echo >&2 "oclint not found, analyzing stopped"
exit 1
fi

hash xctool &> /dev/null
if [ $? -eq 1 ]; then
echo >&2 "xctool not found, analyzing stopped"
exit 1
fi

cd ${SRCROOT}
xctool -workspace MyProject.xcworkspace -scheme MyProject clean
xctool -workspace MyProject.xcworkspace -scheme MyProject -reporter json-compilation-database:compile_commands.json build
oclint-json-compilation-database \
-e Pods \
-- -rc=LONG_LINE=100 \
-rc=NCSS_METHOD=60 \
-rc=MINIMUM_CASES_IN_SWITCH=1 \
| sed 's/\(.*\.\m\{1,2\}:[0-9]*:[0-9]*:\)/\1 warning:/'

Note: the MyProject in the code above must be replaced with your project name. If your project is not managed with a workspace, then these two lines:

xctool -workspace MyProject.xcworkspace -scheme MyProject clean
xctool -workspace MyProject.xcworkspace -scheme MyProject -reporter json-compilation-database:compile_commands.json build

need to be replaced with:

xctool -project MyProject.xcodeproj -scheme MyProject clean
xctool -project MyProject.xcodeproj -scheme MyProject -reporter json-compilation-database:compile_commands.json build
  1. Build the Aggregate you just created. Be patient and wait for the result. Once it is done, you will see the results from OCLint.

Troubleshooting

If the build succeeds but no warnings are shown, there is probably an error somewhere.

  1. Check whether there are warnings in image. I once had a case where the team was not selected correctly, which resulted in no analysis output, or, like me, I selected None.
  2. Check whether there is a .bash_profile file under the ~ directory (hidden file). Use the command below to show hidden files. In Finder, press Command+Shift+G to go to a folder, enter ~, and open the directory to check. If the file does not exist, create one with: cd ~ and then touch .bash_profile.

Show hidden files: defaults write com.apple.finder AppleShowAllFiles TRUE then killall Finder
Hide hidden files again: defaults write com.apple.finder AppleShowAllFiles FALSE then killall Finder

Analysis Results

OCLint warnings are divided into three levels, from highest to lowest: P1, P2, and P3.

P3

  • Long variable name: Long variable name P3 Variable name with 28 characters is longer than the threshold of 20 — the variable name exceeds 20 characters. Of course, the threshold of 20 can be changed, which I will mention later.
  • Inverted logic: Inverted logic, for example:
if (![response isKindOfClass:[NSError class]]) {
    //
}
else{
    //
}
  • Long method: Long method P3 Method with 179 lines exceeds limit of 100 — the code under the method exceeds 100 lines, including comments.
  • Unused method parameter: Unused method parameter P3 The parameter 'section' is unused. This warning is fairly common in iOS development, so it can usually be ignored.
  • Deep nested block: Deep nested block P3 Block depth of 8 exceeds limit of 5, for example deeply nested blocks or nested if/else statements.
  • Collapsible if statements: Collapsible if statements P3, for example:
if (UIUserInterfaceIdiomPhone == UI_USER_INTERFACE_IDIOM()) {
    if (UIKeyboardAppearanceAlert == [self keyboardAppearance]) {
return UIBarStyleBlackTranslucent;
}
}
  • Whether a switch needs default: Switch statements don't need default when fully covered P3. Whether to remove it depends on the situation.

There are of course many other cases.

P2

  • Empty if statement: Empty if statement P2
  • Cyclomatic complexity (CCN): High cyclomatic complexity P2 Cyclomatic Complexity Number 31 exceeds limit of 10, meaning the code is quite complex.
  • NPath complexity: /High npath complexity P2 NPath Complexity Number 384 exceeds limit of 200. I do not fully understand this one.

These are the P2 warnings I have encountered so far. I have not encountered any P1 warnings yet.

Going back to the script code above:

-- -rc=LONG_LINE=300 \
-rc=NCSS_METHOD=60 \

These are the parameter settings provided by OCLint. LONG_LINE represents the maximum number of characters per line of code, and NCSS_METHOD represents the maximum number of non-comment source lines in a method. Other parameters in version 0.8dev include:

CYCLOMATIC_COMPLEXITY
Cyclomatic complexity of a method, default value is 10

LONG_CLASS
Number of lines for a C++ class or objc interface, category, protocol, and implementation, default value is 1000

LONG_LINE
Number of characters for one line of code, default value is 100

LONG_METHOD
Number of lines for a method or function, default value is 50

MINIMUM_CASES_IN_SWITCH
Count of case statements in a switch statement, default value is 3

NPATH_COMPLEXITY
NPath complexity of a method, default value is 200

NCSS_METHOD
Number of non-commenting source statements of a method, default value is 30

NESTED_BLOCK_DEPTH
Depth of a block or compound statement, default value is 5

Unfortunately, there is no parameter related to Unused method parameter.

In short, OCLint analysis is still useful as a reference for improving code readability and maintainability.

This post is licensed under CC BY 4.0 by the author.