Navigation

index

next |

OCLint 0.7 documentation »

OCLint Documentation Contents

Overview

Features

Current Status

Get Started

Get Involved

Introduction

Download

Building OCLint

Installation

Tutorial

Directions to Safe Use

Manual

oclint Manual

oclint-json-compilation-database Manual

oclint-xcodebuild Manual

User Guide

Using OCLint with CMake

Using OCLint with Bear

Using OCLint with xcodebuild

Using OCLint with xctool

Using OCLint in Xcode

Using OCLint with Jenkins

How-To

Suppress OCLint Warnings

Customization

Customizing Rules

Customizing Reports

Rule Index

Basic

Convention

Empty

Migration

Naming

Redundant

Size

Unused

OCLint Internals

Core Module

Metrics Module

Rules Module

Reporters Module

Development

System Requirements

Checking Out Code

Compiling and Testing

Writing Custom Rules

Writing Custom Reporters

Scaffolding

Eating Your Own Dog Food

Open Projects

Related Clang Knowledge Base

Coding Standards

Release Notes

0.7

0.6

0.4.3

0.4.2

0.4.1

0.4

0.2.6

0.2.4

0.2

Modified BSD License

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Overview

OCLint is a static code analysis [http://en.wikipedia.org/wiki/Static_program_analysis] tool for improving quality and reducing defects by inspecting C, C++ and Objective-C code and looking for potential problems like possible bugs, unused code, complicated code, redundant code, code smells, bad practices, and so on.

Features

Static code analysis is a critical technique to detect defects that aren’t visible to compilers. OCLint automates this inspection process with advanced features:

Relying on the abstract syntax tree [http://en.wikipedia.org/wiki/Abstract_syntax_tree] of the source code for better accuracy and efficiency; False positives are mostly reduced to avoid useful results sinking in them.

Dynamically loading rules into system, even in the runtime.

Flexible and extensible configurations ensure users in customizing the behaviors of the tool.

Command line invocation facilitates continuous integration [http://martinfowler.com/articles/continuousIntegration.html] and continuous inspection of the code while being developed, so that technical debts can be fixed early on to reduce the maintenance cost.

Current Status

OCLint is far from finished but is being continuously improved in many aspects, e.g. accuracy, performance and usability.

OCLint started as a research project (defense poster [http://www.cs.uh.edu/news-events/thesis-defenses/2012/04.02-lQi.html]) at the University of Houston [http://www.uh.edu]. Since then, OCLint has been rewritten and grown to be a 100% open source project. OCLint is designed to serve both academia and industry. Our goal is to make it a must-have tool for developers who program in C, C++ and Objective-C languages.

OCLint is compatible with Mac OS X and various Linux distributions.

Get Started

There is a large change that pre-compiled binaries are ready for you to download. It’s also recommended to start with getting the release code and building it. We can then install and run OCLint.

Get Involved

Please also consider getting involved [http://oclint.org/community.html] in the OCLint community. All kinds of contributions, like giving feedback, start a discussion, filing bug reports, request new features, best of all, submitting a patch or two, are appreciated.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Introduction

Download

Choosing the Right Version

Choosing Pre-Compiled Binaries

Choosing Source Code

Building OCLint

System Requirements

Prepare LLVM/Clang

Build OCLint

Verify Your Build

Installation

Option 1: Directly Add to PATH

Option 2: Copy OCLint to System PATH

Verify Installation

Tutorial

Something Smells Here

Building Sample Code (Optional)

Checking Single File

For Projects with Multiple Files

Understanding Report

Directions to Safe Use

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Introduction »

Download

All release downloads can be found at OCLint website download page [http://oclint.org/downloads.html].

Choosing the Right Version

Development

We keep our codebase stable by running continuous integrations on various platforms. Thus, it’s safe to use the latest development version and get access to new features. However, certain things are under development and may not meet release standard.

Stable

Latest official release is the most stable version, and meanwhile, is easier to get support from the entire community.

Previous

Previous release is the second latest stable version, you can still get support from us. But pay attention, it will be archived when next version releases. In addition, deferring upgrading your development toolset is a type of technical debt that you should avoid.

Unsupported

Choosing archived versions without supports.

This documentation is updated for OCLint version 0.7.

Choosing Pre-Compiled Binaries

Pre-compiled binaries are considered to ease you get started. OCLint binaries depend on very little and fundamental system standard libraries. Each should properly works on the platform it specifies. However, there are rare cases that these binaries do not suit you well. If the compiled binary doesn’t work on your machine, consider building OCLint locally.

When download process is finished, see installation document for next step.

Choosing Source Code

All source code releases contain every module that is necessary for compilation and execution.

Different from development codebase, in which all dependencies are caught up to the latest version and debug flags are enabled, in released codebase, everything is finalized and optimized for that particular version.

Read how to build OCLint when you have source code on hand.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Introduction »

Building OCLint

This page presents you a shortcut of building OCLint release version.

Note

If you are looking for compiling and testing OCLint in debug mode for development purposes, please move onto development section.

System Requirements

See LLVM System Requirements [http://llvm.org/docs/GettingStarted.html#requirements]

Apache Subversion [http://subversion.apache.org/]

CMake [http://www.cmake.org/]

Prepare LLVM/Clang

Checkout LLVM/Clang

cd oclint-scripts

./checkoutLLVMClang.sh tags/RELEASE_33/final

cd ..

Build LLVM/Clang

cd oclint-scripts

./buildClang.sh release

cd ..

Build OCLint

cd oclint-scripts

./buildAll.sh

cd ..

Verify Your Build

cd build/oclint-release/bin

./oclint

You should get:

$ ./oclint
oclint: Not enough positional command line arguments specified!
Must specify at least 1 positional arguments: See: ./oclint -help

Now, let’s move onto installation.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Introduction »

Installation

No matter you have downloaded a pre-compiled binary distribution or have built OCLint from scratch by yourself, now you should have an OCLint release with which file tree similar to this:

oclint-release
|-bin
|-lib
|---clang
|-----3.3
|-------include
|-------lib
|---oclint
|-----rules
|-----reporters

In fact, you can execute oclint from bin directory now.

In order to easily invoke all OCLint executables, it’s recommended to install OCLint to PATH, the environment variable that tells system which directories to search for executable files.

Option 1: Directly Add to PATH

You can add OCLint release folder directly to PATH by appending the following code block into your .bashrc or .bash_profile that is read when terminal launches.

OCLINT_HOME=/path/to/oclint-release
export PATH=$OCLINT_HOME/bin:$PATH

Option 2: Copy OCLint to System PATH

You can also copy OCLint to system PATH. There is an example that presumes /usr/local/bin is in the PATH.

sudo cp bin/oclint* /usr/local/bin/ (require root permission)

sudo cp -rp lib/* /usr/local/lib/ (require root permission)

Dependency libraries are required to be put into correct directory, because oclint executable searches $(/path/to/bin/oclint)/../lib/clang, $(/path/to/bin/oclint)/../lib/oclint/rules and $(/path/to/bin/oclint)/../lib/oclint/reporters for required builtin headers and dynamic libraries.

Verify Installation

Open a new command line terminal, and simply execute oclint, you should get:

$ oclint
oclint: Not enough positional command line arguments specified!
Must specify at least 1 positional arguments: See: ./oclint -help

That’s it – you can now move onto tutorial.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Introduction »

Tutorial

This tutorial walks you through the inspection of a piece of small but smelly C++ source code. By the end of this tutorial, you should be able to

apply OCLint on a single file

configure OCLint with very basic compiler flags

understand the output

Throughout this tutorial, we will also lead you to the detail pages if you are interested in certain steps and are willing to know more.

Something Smells Here

Create a sample.cpp file with the content below:

int main() {
    int i = 0, j = 1;
    if (j) {
        if (i) {
            return 1;
            j = 0;
        }
    }
    return 0;
}

Building Sample Code (Optional)

There is actually not necessary to build the code prior to run OCLint against it. However, since finding the correct arguments becomes one of the most frequently asked questions, this step is trying to help you convert your compiler flags to the ones that OCLint requires.

Note

This step, however, doesn’t intent to show you how to find the correct compiler flags, thus, some level of knowledge about compiler flags is a prerequisite.

$ CC -c sample.cpp // step 1: compiling generates sample.o
$ CC -o sample sample.o // step 2: linking generates sample executable file

// Change CC to your favorite compiler that is GCC-compatible, e.g. g++ and clang++

$ ./sample // execute the binary
$ echo $? // output of a 0 means the code has been successfully built

We just took two sequential steps to generate the binary, step 1 compiles the code, and step 2 links. We are only interested in step 1 because that’s all compiler flags you need to give to OCLint. Here in this case, the compiler flag is -c, and inspected source file is sample.cpp.

If you cannot pass through this step, don’t give up, there are some tools try to help, like CMake and Bear (for Make). In addition, we also provide two helper programs oclint-json-compilation-database and oclint-xcodebuild (for Mac Xcode users) could help find the arguments for OCLint.

Checking Single File

OCLint checks on single file with the following format:

oclint [options] <source> -- [compiler flags]

So, the command that applies to the sample source is

$ oclint sample.cpp -- -c

To change OCLint behavior, change the [options] before the source; to alter the compiler behavior, change the [compiler flags] after the -- separator. A complicated example might look like this:

$ oclint -report-type html -o report.html sample.cpp -- -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS -I/usr/include -I/usr/local/include -c

For detail about OCLint options, see oclint manual.

For Projects with Multiple Files

The approach describe in the previous section works perfectly if you want to apply OCLint against one single file or a few files. The inspection process is fast, and making changes to arguments is easy.

While working on a project with a group of source files, you definitely prefer inspecting the entire project and having one report consists of all results.

When they share the same compiler flags, you can still do

oclint [options]  <source0> [... <sourceN>] -- [compiler flags]

However, each source file may have different compiler flags. In this case, OCLint can recognize the compilation database to know the list of source files for analysis, along with the compiler flags used for each time during the compilation phase. It can be considered as a condensed Makefile. So, you can do

oclint -p <build-path> [other options]  <source0> [... <sourceN>]

A more handy helper program that comes with OCLint is oclint-json-compilation-database. If you use OCLint to analyze projects, for the most of the time, you will deal with oclint-json-compilation-database and indirectly talk to oclint.

For people who work on a Mac with Xcode as IDE, you may find Using OCLint with xcodebuild and Using OCLint in Xcode <../guide/xcode.html> documents are helpful.

We also provide guidances for people who use CMake and make as their build system respectively.

Understanding Report

By applying OCLint against the above sample, with the default text reporter, we got the output like this:

Processing: /path/to/sample.cpp.
OCLint Report

Summary: TotalFiles=1 FilesWithViolations=1 P1=0 P2=1 P3=1

/path/to/sample.cpp:4:9: collapsible if statements P3
/path/to/sample.cpp:9:17: dead code P2

[OCLint (http://oclint.org) v0.7]

Basically, you can find the following information in the report:

Summary

total files

files with violations

number of priority 1 violations

number of priority 2 violations

number of priority 3 violations

A list of violations

path to the source file

line number

column number

violated rule

priority

message (if any)

OCLint information

website

release version

Read more about customizing reports.

We hope you have some feelings about OCLint, you can move on with comprehensive manuals and user guides. Also feel free to browse the rest of the content in this documentation for details, back to index or see table of contents. Thank you!

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Introduction »

Directions to Safe Use

We are drafting this document by following the suggestions from Andy Hunt’s proposal [http://blog.toolshed.com/2013/04/directions-for-safe-use.html].

There are many many cool features that we can provide. At the same time, there are restrictions that we currently don’t have a solution but only workarounds. We, as contributors, would like to be honest about the flaws in our tool. We hope these directions to safe use could be beneficial for both OCLint users and contributors -

Users can save time by avoiding falling into the same issues that has already trapped other users for a long time but currently no solution due to the constraints by the tool itself

Contributors, on the other hand, can save efforts by avoiding spending time digging into different aspects but turn out to be the same issue. By saving the time, contributors can use the passion on experimenting new ideas, improving existing features, and fixing the true problems

Alright, let’s go with a few -

Make sure there is no error when compile the code

When there are errors in code compilation, oclint won’t conduct any analysis, and will produce empty report in the end

No white spaces in file name and path [http://oclint.org/news/2013/03/10/no-space-in-file-name-and-path/]

The existence of white spaces can cause problem when use oclint-json-compilation-database and oclint-xcodebuild

We hope you’ll enjoy OCLint, and can get benefits from using it. Look forward to your suggestions. Thank you.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Manual

oclint Manual

Rule Loading Options

Compilation Options

Sources Options

Report Options

Exit Status Options

Debug Options

Other Options

oclint-json-compilation-database Manual

Filter Options

OCLint Options

Debug Options

oclint-xcodebuild Manual

Running oclint-xcodebuild

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Manual »

oclint Manual

When we invoke OCLint, it normally does rule loading, compilation, analysis, and report generation. The options allow us to change the behavior of each step to certain ways that meet our requirements.

See all supported options in OCLint 0.7 by typing oclint -help:

USAGE: oclint [options] <source0> [... <sourceN>]

OPTIONS:
  -R=<directory>              - Add directory to rule loading path
  -fatal-assembler-warnings   - Consider warnings as error
  -help                       - Display available options (-help-hidden for more)
  -max-priority-1=<threshold> - The max allowed number of priority 1 violations
  -max-priority-2=<threshold> - The max allowed number of priority 2 violations
  -max-priority-3=<threshold> - The max allowed number of priority 3 violations
  -o=<path>                   - Write output to <path>
  -p=<string>                 - Build path
  -rc=<parameter>=<value>     - Override the default behavior of rules
  -report-type=<name>         - Change output report type
  -stats                      - Enable statistics output from program
  -version                    - Display the version of this program

-p <build-path> is used to read a compile command database.

    For example, it can be a CMake build directory in which a file named
    compile_commands.json exists (use -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
    CMake option to get this output). When no build path is specified,
    a search for compile_commands.json will be attempted through all
    parent paths of the first input file . See:
    http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an
    example of setting up Clang Tooling on a source tree.

<source0> ... specify the paths of source files. These paths are
    looked up in the compile command database. If the path of a file is
    absolute, it needs to point into CMake's source tree. If the path is
    relative, the current working directory needs to be in the CMake
    source tree and the file must be in a subdirectory of the current
    working directory. "./" prefixes in the relative files will be
    automatically removed, but the rest of a relative path must be a
    suffix of a path in the compile command database.

For more information, please visit http://oclint.org

Rule Loading Options

-R <directory>

Rule loading path can be changed by using -R option. Multiple rule loading paths can be specified to load rules from more than one directories. By default, OCLint searches $(/path/to/bin/oclint)/../lib/oclint/rules for the dyanmic libraries that contain rules.

-rc <paramemter>=<value>

Certain rules have threshold to decide whether to emit violations. These thresholds can be changed by -rc option with a key-value pair.

More detail on changing the behavior in rules loading process during runtime can be found in customizing rules page.

Compilation Options

For the sources that are being inspected, OCLint needs to know the compiler options for each of them. These options are the same arguments for actual compilers, like gcc or clang. There are two alternatives for passing the options to OCLint, namely specifying the compiler options directly to OCLint and using compilation database.

Giving Compiler Options

Compiler options can be given directly to OCLint. It’s quite straight forward, after all OCLint options and sources, append -- separator followed by all compiler options:

oclint [oclint options] <source0> [... <sourceN>] -- [compiler options]

For example, if we are compiling a file by the following clang command:

clang -x objective-c -arch armv7 -std=gnu99 -fobjc-arc -O0 -isysroot /Developer/SDKs/iPhoneOS6.0.sdk -g -I./Pods/Headers -c RPActivityIndicatorManager.m

(Wow, it’s longer than expectation.)

Then when we analyze this code, our OCLint command will be:

oclint [oclint options] RPActivityIndicatorManager.m -- -x objective-c -arch armv7 -std=gnu99 -fobjc-arc -O0 -isysroot /Developer/SDKs/iPhoneOS6.0.sdk -g -I./Pods/Headers -c

Compilation Database

-p <build-path>

Choose the build directory in which a file named compile_commands.json exists. When no build path is specified, a search for compile_commands.json will be attempted through all parent paths of the first input file.

If no compiler options are given explicitly, OCLint requires this compilation database to understand specific build options for each source file. Currently it supports compile_commands.json file. See oclint-json-compilation-database for detail.

Sources Options

We specify the path to all the source files we want to inspect. Multiple files can be analyzed with one invocation.

Report Options

-o <path>

Instead of piping output to console, -o will redirect the report to the <path> you specified.

-report-type <name>

Change output report type, by default, plain text report is used

See customizing reports for detail.

Exit Status Options

-max-priority-1 <threshold>

The max allowed number of priority 1 violations

-max-priority-2 <threshold>

The max allowed number of priority 2 violations

-max-priority-3 <threshold>

The max allowed number of priority 3 violations

This option helps continuous integration and other build systems. OCLint returns with one of the five exit codes below

0 - SUCCESS

1 - RULE_NOT_FOUND

2 - REPORTER_NOT_FOUND

3 - ERROR_WHILE_PROCESSING

4 - ERROR_WHILE_REPORTING

5 - VIOLATIONS_EXCEED_THRESHOLD

OCLint always return code zero for success execution with the number of violations under an acceptable range. Exit code other than zero means there are something wrong.

For example, when the compilation process fails, an exit code of 3 will be returned. It means either the compiler options have not been set correctly, or the source code has errors.

When the number of violations in any of the priorities is larger than the maximum tolerance, OCLint returns with an exit status code of 5. By default, less than 20 priority 3 violations are allowed, 10 violations is maximum for priority 2, and no priority 1 violation can be tolerated. Too many violations result in bad code quality, if that happens, OCLint intends to fail the build system.

Debug Options

-debug

invoke OCLint in debug mode.

If OCLint is built in the debug model, -debug outputs deeper message from OCLint invocation. It prints messages that can help understand the overall progress of OCLint analysis. Please aware that this is only available when OCLint is built with debug flag on.

Other Options

-version

Show version information about OCLint, LLVM and some environment variables.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Manual »

oclint-json-compilation-database Manual

oclint-json-compilation-database is a helper program that eases running OCLint against a set of source code files. Instead of specifying compiler flags for each file when oclint is invoked, these compiler flags could be collected and persistently saved to compile_commands.json file in JSON Compilation Database format.

See also

Please read JSON Compilation Database Format Specification [http://clang.llvm.org/docs/JSONCompilationDatabase.html] for detail.

oclint-json-compilation-database can fetch necessary information from compile_commands.json and kick off oclint with these compiler flags under the hook for code analysis. See the usage by typing oclint-json-complication-database -help:

usage: oclint-json-compilation-database  [-h] [-v] [-debug] [-i INCLUDES]
                                         [-e EXCLUDES]
                                         [oclint_args [oclint_args ...]]

OCLint for JSON Compilation Database (compile_commands.json)

positional arguments:
  oclint_args           arguments that are passed to OCLint invocation

optional arguments:
  -h, --help            show this help message and exit
  -v                    show invocation command with arguments
  -debug, --debug       invoke OCLint in debug mode
  -i INCLUDES, -include INCLUDES, --include INCLUDES
                        extract files matching pattern
  -e EXCLUDES, -exclude EXCLUDES, --exclude EXCLUDES
                        remove files matching pattern

Filter Options

-i INCLUDES, -include INCLUDES, –include INCLUDES

Extract files matching pattern from compile_commands.json or prior matching result

-e EXCLUDES, -exclude EXCLUDES, –exclude EXCLUDES

Remove files matching pattern from compile_commands.json or prior matching result

Sometimes, we may be interested in only a subset of entire codebase defined in compile_commands.json, and just want to inspect these sources. To do that, we can use filter options to get this subset. Since oclint-json-compilation-database is written in Python, so the matching pattern needs to follow Python regular expression syntax [http://docs.python.org/2/library/re.html#re-syntax]. In addition, multiple filters can be chained to get the file set we need for analysis.

OCLint Options

Remember there are many options that we can use to change the behavior of OCLint itself? Sure, and we can also ask oclint-json-compilation-database to pass through these options when it invokes oclint under the hook.

Since all compiler options are defined in compile_commands.json file, we don’t need to tell oclint about them this time. But by following the same idea, now, the OCLint options can be given to oclint-json-compilation-database by appending -- separator followed by all OCLint options:

oclint-json-compilation-database [<filter0> ... <filterN>] -- [oclint options]

Debug Options

-v

show invocation command with arguments

-debug

invoke OCLint in debug mode

oclint-json-compilation-database generates oclint command with corresponding options based on our settings of all filters and OCLint options, and eventually call oclint for us. Debug option -v outputs the final oclint invocation command, it’s helpful for debugging purposes, because if we run the generated oclint command directly in the console, we will get the identical result same as using oclint-json-compilation-database.

More than that, if OCLint is built in the debug model, -debug outputs deeper message from OCLint invocation. It prints messages that can help understand the overall progress of OCLint analysis. Please aware that this is only available when OCLint is built with debug flag on.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Manual »

oclint-xcodebuild Manual

For developers who use Xcode, oclint-xcodebuild is a helpful program that extracts adequate compiler options from xcodebuild execution log, converts them into JSON Compilation Database format, and save it into compile_commands.json file.

See also

Read Apple’s official xcodebuild Manual Page [https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/xcodebuild.1.html] from Mac Developer Library. To understand how oclint-xcodebuild can be applied in your workflow, please move onto Using OCLint with xcodebuild document.

Running oclint-xcodebuild

If a xcodebuild.log file is at the current working directory. Simply run

oclint-xcodebuild

In case the xcodebuild log is stored in a file with name other than xcodebuild.log, append the path to the log file like

oclint-xcodebuild /path/to/xcodebuild/log

When certain files are compiled by Xcode but we want to exclude them from the compilation database, we could filter them out by

oclint-xcodebuild -e <exclude_pattern_regex> -l </path/to/xcodebuild/log>

The compile_commands.json will be generated to the current working directory.

Warning

It’s highly recommended to avoid having spaces in your file name or file path. It’s a good practice. Meanwhile, even though oclint itself supports spaces in path, oclint-json-compilation-database and oclint-xcodebuild still have issues handling spaces in path.

Note

oclint-xcodebuild is still an experimental project. The success of it depends on various things, e.g. Mac OS X version, the Xcode version and project settings. However, since developers who use Xcode are familiar with Apple’s manner of supporting only the latest version and one previous version, so oclint-xcodebuild tries to follow this convention. Your feedback is warmly welcome to help improve this helper program.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

User Guide

Using OCLint with CMake

Prerequisite

Background

Generating compile_comamnds.json

Using compile_commands.json

Running OCLint

Using OCLint with Bear

Prerequisite

Background

Generating compile_comamnds.json

What’s Next

Using OCLint with xcodebuild

Prerequisite

Background

Running xcodebuild

Capturing Output

Running oclint-xcodebuild

Running oclint-json-compilation-database

Discussions

Using OCLint with xctool

Prerequisite

Background

Running xctool with json-compilation-database Reporter

Running oclint-json-compilation-database

Using OCLint in Xcode

Prerequisite

Background

Setting up Target

Running Analysis

Using OCLint with Jenkins

Prerequisite

Background

Setting up Project

Configuring OCLint and PMD Plugin

Running Analysis

Monitoring Results

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

User Guide »

Using OCLint with CMake

This document shows how to apply OCLint to the projects which use CMake as build system.

Prerequisite

CMake [http://www.cmake.org/]

oclint Manual

oclint-json-compilation-database Manual

Background

CMake is able to generate JSON Compilation Database file compile_commands.json with no hassle at all. If a project uses CMake as its build system, then applying OCLint is a quite easy task.

Generating compile_comamnds.json

Simply add -DCMAKE_EXPORT_COMPILE_COMMANDS=ON to the existing cmake command, like

cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON path/to/source-root

As a result, the compile_commands.json file is generated in the CMake build folder.

That’s it!

Using compile_commands.json

We can leave the compile_commands.json file here in the build directory, and use -p option to specify this file for oclint.

But in order to use oclint-json-compilation-database, it’s required to copy or link this file to our source directory, for example:

copy the file

cp `pwd`/compile_commands.json /path/to/source-root

link the file

ln -s `pwd`/compile_commands.json /path/to/source-root

Running OCLint

Now we can use oclint by

oclint -p <build path> <source0> [... <sourceN>]

build path is the path to the folder that contains compile_commands.json.

In addition, we can use oclint-json-compilation-database for code analysis. In this case, simply enter

oclint-json-compilation-database

For advanced usage, detail instructions can be found in oclint and oclint-json-compilation-database manuals respectively.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

User Guide »

Using OCLint with Bear

This document shows how to apply OCLint to the projects which use Make [http://en.wikipedia.org/wiki/Make_(software)] and other build systems in unix-like operating systems.

Prerequisite

Bear [https://github.com/rizsotto/Bear]

man make

oclint Manual

oclint-json-compilation-database Manual

Background

Bear is a very handy tool to generate compilation database during the build process. Bear is a very important supplement especially for those who don’t use CMake as build system. Bear can be applied in a wider circumstances, because it injects into the build process, and intercepts the exec calls to understand the compilation details.

Generating compile_comamnds.json

By following the instructions on Bear README [https://github.com/rizsotto/Bear/blob/master/README.md], we could have bear ready to use.

For example, if want to generate the compile_command.json for a project using make, we can easily use bear by

$ /path/to/bear -- make

What’s Next

The rest of the process is as same as those who use CMake. Please refer to the other document.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

User Guide »

Using OCLint with xcodebuild

This document goes through the happy path of using OCLint to analyze the code quality of a Xcode project with xcodebuild.

See also

If you use Facebook’s xctool [https://github.com/facebook/xctool] to build your Xcode projects, please use the json-compilation-database reporter to make things much easier. We highly recommend you start to use xctool as a replacement for xcodebuild.

Prerequisite

oclint Manual

oclint-json-compilation-database Manual

oclint-xcodebuild Manual

Apple’s official xcodebuild Manual Page [https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/xcodebuild.1.html]

Background

OCLint recognizes a file called compile_commands.json to figure out the compiler options for parsing each file. For Xcode users, since all these compiler options are implicitly configured in Xcode build settings, we can see what actually happens when we invoke xcodebuild in terminal. Our approach is to capture the log of xcodebuild output, use oclint-xcodebuild to extract the adequate compiler options, convert them into JSON Compilation Database format, and save it into compile_commands.json file. Then we can use oclint-json-compilation-database to run analysis.

Running xcodebuild

Running xcodebuild is a quite simple task to some people by figuring out the correct options for xcodebuild. However, some people may feel it’s not intuitive, so be patient, and take your time. You may find many online tutorials and blog posts that may help.

Basically, let’s say we have a DemoProject, to know all the options we have, enter xcodebuild -list:

$ xcodebuild -list
Information about project "DemoProject":
    Targets:
        DemoProject
        DemoProjectTests

    Build Configurations:
        Debug
        Release

    If no build configuration is specified and -scheme is not passed then "Release" is used.

    Schemes:
        DemoProject

We can map these options back to the Xcode GUI:

Based on our choices in Xcode, we can set the corresponding options for xcodebuild. For instance, we can build our DemoProject project with

xcodebuild -target DemoProject -configuration Debug -scheme DemoProject

We should see detail xcodebuild invocations with a ** BUILD SUCCEEDED ** in the end. Great!

There are more options for xcodebuild, like workspace, arch, sdk, etc, we can apply them when necessary.

Capturing Output

We need to save the xcodebuild output to a log file, by convention, name it xcodebuild.log. We can use xcodebuild <options> | tee xcodebuild.log to pipe every line of the output to xcodebuild.log file.

Running oclint-xcodebuild

By running oclint-xcodebuild in the project root folder, a compile_command.json file should be generated.

Running oclint-json-compilation-database

Excellent! Last step, we can kick off code analysis by oclint-json-compilation-database. We can filter the JSON compilation database, and analyze on the files we are interested. We can also change the OCLint behaviors to meet our specific requirements.

Discussions

Clean Build

If a source file has been built by xcodebuild, and it’s not been modified since last build, then it might not be compiled again when you invoke xcodebuild the second time. In other words, if it happens, this file won’t be shown in the log. So we won’t see it in the compile_commands.json. To avoid that, use clean build by removing all build products and intermediate files from the build directory.

However, cleaning and building the entire project takes longer time, especially for those big projects. In this case, if file structure hasn’t been changed, and build settings haven’t been modified, then it’s okay to keep the existing xcodebuild.log and compile_commands.json to save time.

If the xcodebuild build can be guaranteed to be successful with the options specified, then we could also use -dry-run option to build the project without actually running the commands, so that we can still capture the xcodebuild log but with reduced time.

Save to Repository

compile_commands.json is platform sensitive. Whenever the environment has been changed, for example, upgrading Mac OS, upgrading Xcode version, switch to another SDK, and so on, please remove the existing xcodebuild.log and compile_commands.json, capture xcodebuild log again with the updated options, and re-generate new compile_commands.json.

Checking compile_commands.json into source code repository is not necessary. Instead, always generate a new compile_comamnds.json when anything changes.

However, we could write the entire process into a bash script, and check in this script. So that, all developers who work on the project can run this script and generate the compile_commands.json file that works best for his or her local environment.

See also

You might also be interested in using OCLint in Xcode.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

User Guide »

Using OCLint with xctool

This document goes through the happy path of using OCLint to analyze the code quality of a Xcode project with xctool.

Prerequisite

oclint Manual

oclint-json-compilation-database Manual

xctool README [https://github.com/facebook/xctool/blob/master/README.md]

Background

xctool is a drop-in replacement for Apple’s xcodebuild, it makes things much easier to build Xcode projects. It eases continuous integration in many ways. xctool supports generating the report in JSON Compilation Database format, which can be used by OCLint to understand all the compiler flags in order to analyze the code.

Running xctool with json-compilation-database Reporter

Running xctool is quite straight forward, for example, the command below is simple build the project and generates the compile_commands.json file under the current folder.

path/to/xctool.sh \
  -project YourProject.xcodeproj \
  -scheme YourScheme \
  -reporter json-compilation-database:compile_commands.json \
  build

xctool also supports an .xctool-args file to preserve the command arguments, like workspace, scheme, configuration, etc. If we have .xctool-args ready, then we could simply run

xctool -reporter json-compilation-database:compile_commands.json build

to get the compile_commands.json file.

We can use xctool clean to clean the build in order to have a full list of all compiling files the next time we call xctool build.

Running oclint-json-compilation-database

Now, by having the compile_commands.json file, we can run the code analysis by simply call

oclint-json-compilation-database

Or with your customizations.

See also

With the great help from xctool, you could even show OCLint warnings in Xcode.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

User Guide »

Using OCLint in Xcode

This document shows one solution of using OCLint to analyze the code quality of a Xcode project.

Prerequisite

oclint-xcodebuild Manual

Apple’s official xcodebuild Manual Page [https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/xcodebuild.1.html]

Using OCLint with xcodebuild

or

Using OCLint with xctool

Background

This idea was originally posted in this blog [http://gavrix.wordpress.com/2013/02/28/integrating-oclint-in-xcode/]. We hope to share it with more developers, and hope to motivate more ideas.

Setting up Target

Add a new target in the project, and choose Aggregate as the template.

Name the new target, here we simply call it “OCLint”, you could have more than one targets that focus on different aspects of the code analysis.

Add a new build phase in the target we just created. Choose And Run Script for the phase type.

In the script editor, we could enter the script which does the real work. We can also modify the script from this very generic version [https://gist.github.com/lqi/5358513]. We may need to change the xcodebuild options to use a particular scheme or target. In addition, based on the discussions we had, we can decide whether to use clean and dry run features.

For xctool users, the script can be largely simplified to something like this [https://gist.github.com/lqi/5705477]

Running Analysis

Choose the correct build scheme, here we choose OCLint.

Click to build, or use the shortcut Command+B.

When the progress bar scrolls to the very right, the analysis is done, then we can check out the analysis results same as compile warnings.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

User Guide »

Using OCLint with Jenkins

This document shows how to integrate OCLint into Jenkins CI, and render the graphic report by the cooperation between Jenkins’ PMD Plugin and OCLint’s PMD reporter.

Prerequisite

Jenkins CI [http://jenkins-ci.org/]

PMD Plugin for Jenkins CI [https://wiki.jenkins-ci.org/display/JENKINS/PMD+Plugin]

Knowing how to configure Jenkins to run conitnuous integration [http://martinfowler.com/articles/continuousIntegration.html] for the project

Knowing how to generate compile_commands.json for the project

Read other guides in this chapter for references

oclint Manual

oclint-json-compilation-database Manual

Background

From the very beginning of OCLint project, we have always taken continuous integration into serious consideration. OCLint facilitates this process a lot. It generates the certain type of report as artifact, and it fails your build if any level of violations exceeds the threshold.

In order to utilize the Jenkins CI, we have introduced the PMD reporter that converts the analysis results into the format very close to PMD reports, so that the PMD plugin inside Jenkins can easily picks up this output, categorizes and renders graphic reports for us.

The idea was originally developed by Stephan Esch in his blog post [http://maplesteve.com/2013/03/10/jenkins-pmd-analysis-for-objective-c-with-oclint] along with his contribution of writing PMDReporter for us.

Setting up Project

Create a new free-style project

Set up adequate steps for continuously building the project

Configuring OCLint and PMD Plugin

Add a new build step as an execute shell

Set up command used for OCLint analysis

In addition to the script shown in the following screenshot, we may also need to write the compile_commands.json generation commands in advance.

In some cases, oclint binary suits better than oclint-json-compilation-database

We need to set the report type to pmd

Give a name to the output artifact, we will need this file in the following step

Add a new post-build action, and choose Publish PMD analysis results

Enter the output artifact name that matches previous step

Running Analysis

Same as running regular Jenkins build, it might be triggered by time, by pinging the source control management, and manually. you can see the build history and current build progress.

Monitoring Results

When the build finishes successfully, we now can go into that build. On the left sidebar, click PMD Warnings to see the report. Following is a screenshot of sorting the results by the type of the rules.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

How-To

Suppress OCLint Warnings

Annotations

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

How-To »

Suppress OCLint Warnings

There are two scenarios you might want to suppress an warning:

the standard for certain code measurement is controversial

it is a false positive

There are several methods you could consider to suppress OCLint rule violations:

If the warning you need to suppress also appeals to other OCLint users, e.g. a false positive

Patch test cases, amend the rule to make tests pass, and submit a pull request. Your help would be greatly appreciated by everyone

Open an issue on github or discuss with us in the mailing list

If the standard of your project is slightly different from OCLint default settings

Consider change those rules’ thresholds according to your standard

If certain rules are really annoying

Remove them from the rule search path

If it is a case-by-case thing, and only particular places need to be suppressed

Use annotation described below

Annotations

By adding annotations to the source code, you can communicate with OCLint and order it to discard certain types of rule violations. However, for a better code quality purposes, not every rule can be suppressed. Currently, you can suppress the following warnings:

unused method parameter

high cyclomatic complexity

high npath complexity

high ncss method

In addition to these rules, please feel free to modify the implementation of other rules to enable this feature by yourself.

Annotation Syntax

You can suppress one rule like this:

__attribute__((annotate("oclint:suppress[unused method parameter]")))

Or, you can suppress multiple rules at the same time, like this:

__attribute__((annotate("oclint:suppress[high cyclomatic complexity]"), annotate("oclint:suppress[high npath complexity]"), annotate("oclint:suppress[high ncss method]")))

OCLint also allows you to suppress all supported rule warnings by:

__attribute__((annotate("oclint:suppress")))

Warning

Only supported rule warnings can be suppressed. In other words, if suppress feature is not enabled for a particular rule, e.g. long method, then neither __attribute__((annotate("oclint:suppress[long method]"))) nor __attribute__((annotate("oclint:suppress"))) will help. In this case, we believe long methods are always the culprit of so many other code smells, thus we intent to discard the support for it. However, again, you can quickly learn how to enable it by looking at other supported rules.

Examples

bool __attribute__((annotate("oclint:suppress"))) aMethod(
    int aParameter __attribute__((annotate("oclint:suppress[unused method parameter]"))))
{
    // code

    return true;
}

- (IBAction)turnoverValueChanged:
      (id) __attribute__((annotate("oclint:suppress[unused method parameter]"))) sender
{
    [self calculateTurnover];
}

- (void)dismissAllViews:(id) __attribute__((annotate("oclint:suppress"))) currentView
        parentView:(id) __attribute__((annotate("oclint:suppress"))) parentView
        __attribute__((annotate("oclint:suppress")))
{
    [self dismissTurnoverView];
    // plus 30+ lines of code of dismissing other views
}

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Customization

Customizing Rules

Selecting Rules for Inspection

Rule Thresholds

Customizing Reports

Report Options

Report Types

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Customization »

Customizing Rules

OCLint is a rule based code analysis tool. Rule system is designed to be very extensible and flexible. So it’s easy to customize rules in many ways, like making particular ruleset for certain projects, categorize them and load them from different locations, change the behavior of rules during runtime. We can even easily write our own custom rules, and plug them into OCLint system without rebuilding OCLint. We can find how to customize rules in this document, and how to custom rules in another page.

Selecting Rules for Inspection

By default, rules will be loaded from $(/path/to/bin/oclint)/../lib/oclint/rules directory, we name it rule search path. We can change the rule search path with -R <directory> option. Multiple locations can be specified, and rules in all these directories will be loaded.

Rule directory consists of a group of dynamic libraries, with extension .so in Linux and .dylib in Mac OS X. We can easily copy a subset of these rules into another folder, and use this new ruleset for particular projects. We call this plug-and-use rule loading mechanism - all dynamic libraries are loaded when OCLint searches through rule loading paths. So, when certain rules do not suite our project, simply remove them; and dragging and dropping new rules into the rule loading paths makes them immediate available for use.

Rule Thresholds

Certain rules emit violations only when the metrics of the source code exceed the thresholds. For example, according to [McCabe76], a reasonable cyclomatic complexity number for a method should be less than 10. So, default threshold in CyclomaticComplexityRule is set to 10. However, this value may not be the best for your project, you might either be okay with a more complicated codebase or you decide to push your team hard with a more restrict threshold. Then you can change this threshold by using -rc CYCLOMATIC_COMPLEXITY=<new_value> option.

Here is a list of all thresholds defined in OCLint 0.7:

CYCLOMATIC_COMPLEXITY

Cyclomatic complexity of a method, default value is 10

LONG_CLASS

Number of lines for a C++ class or Objective-C 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

See also

To extend the customization, you can write your own rules to gain more capabilities.

[McCabe76]
McCabe, T. J. (1976). A Complexity Measure. IEEE Transactions on Software Engineering, SE-2(4), 308-320. doi:10.1109/TSE.1976.233837

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Customization »

Customizing Reports

OCLint currently supports generating multiple types of reports based on the demands of different use cases. The generation for each report type is handled by a reporter. All reporters are collected in oclint-reporters module.

See also

You can write your own reporters to extend OCLint with more capabilities.

Report Options

OCLint uses plain text reporter by default, so usually we don’t need to explicitly specify -report-type text flag. In order to use other reporter, add -report-type <report_name> to oclint command.

Some reports are better to be viewed in places other than the console. For example, web browser is a good place for reading HTML reports, and PMD report has a better visual rendering effect in continuous integration systems like Jenkins. In these cases, -o <path> option can help redirect the report to a file instead of console.

By combining both options, for example, outputting the result in HTML format to oclint_result.html file can be achieved by

oclint -report-type html -o oclint_result.html <sources> -- <compiler_flags>

Report Types

We currently have the following reporters. The names in the parentheses are the values we are going to use for report-type option.

Plain Text Report (text)

Plain text report is designed for directly outputting results to console.

Report starts with the summary of the inspection, it consists of number of total files, number of files with violations, and number of violations for three different priorities.

The output of each violation is formatted similar to compiler errors. Each line in the report indicates a violation. It starts with the file name, line, and column of the source code that the violation occurs. The name of the violated rule is printed after, followed by the priority of the rule. OCLint also outputs descriptions if current violation has any.

Sample text report

HTML Report (html)

HTML reporter is browser friendly with better readability. The entire report follows the same order as the text report, but with a nicer structure of sections, paragraphs, and annotations. Violations are highlighted with different colors according to the priority.

Sample HTML report

XML Report (xml)

XML reporter produces an XML report of the results.

Note

This XML format is still being refined and is subject to change.

Sample XML report

JSON Reporter (json)

JSON reporter produces an JSON report of the results.

Note

This JSON format is still being refined and is subject to change.

Sample JSON report

PMD Reporter (pmd)

Since many existing continuous integration (CI) systems support PMD [http://pmd.sourceforge.net/] for Java developers, PMD reporter outputs the XML report that follows the PMD report format. So that these CI systems can pick up the output and render better graphic results.

Sample PMD report

See also

We feel grateful if you could help us write plugins for continuous integration systems.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Rule Index

OCLint 0.7 includes 58 rules.

Basic

BitwiseOperatorInConditional

BrokenNilCheck

BrokenNullCheck

BrokenOddnessCheck

CollapsibleIfStatements

ConstantConditionalOperator

ConstantIfExpression

DeadCode

DoubleNegative

ForLoopShouldBeWhileLoop

GotoStatement

MisplacedNilCheck

MisplacedNullCheck

MultipleUnaryOperator

ReturnFromFinallyBlock

ThrowExceptionFromFinallyBlock

Convention

AvoidBranchingStatementAsLastInLoop

DefaultLabelNotLastInSwitchStatement

InvertedLogic

JumbledIncrementer

MissingBreakInSwitchStatement

NonCaseLabelInSwitchStatement

ParameterReassignment

SwitchStatementsShouldHaveDefault

TooFewBranchesInSwitchStatement

Empty

EmptyCatchStatement

EmptyDoWhileStatement

EmptyElseBlock

EmptyFinallyStatement

EmptyForStatement

EmptyIfStatement

EmptySwitchStatement

EmptyTryStatement

EmptyWhileStatement

Migration

ObjCBoxedExpressions

ObjCContainerLiterals

ObjCNSNumberLiterals

ObjCObjectSubscripting

Naming

LongVariableName

ShortVariableName

Redundant

RedundantConditionalOperator

RedundantIfStatement

RedundantLocalVariable

RedundantNilCheck

UnnecessaryElseStatement

UselessParentheses

Size

CyclomaticComplexity

LongClass

LongLine

LongMethod

NcssMethodCount

NestedBlockDepth

NPathComplexity

TooManyFields

TooManyMethods

TooManyParameters

Unused

UnusedLocalVariable

UnusedMethodParameter

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Rule Index »

Basic

BitwiseOperatorInConditional

Since: 0.6

Checks for bitwise operations in conditionals. Although being written on purpose in some rare cases, bitwise operations are considered to be too “smart”. Smart code is not easy to understand.

This rule is defined by the following class: oclint-rules/rules/basic/BitwiseOperatorInConditionalRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/basic/BitwiseOperatorInConditionalRule.cpp]

Example:

void example(int a, int b)
{
    if (a | b)
    {
    }
    if (a & b)
    {
    }
}

BrokenNilCheck

Since: 0.7

The broken nil check in Objective-C in some cases returns just the opposite result.

This rule is defined by the following class: oclint-rules/rules/basic/BrokenNullCheckRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/basic/BrokenNullCheckRule.cpp]

Example:

+ (void)compare:(A *)obj1 withOther:(A *)obj2
{
    if (obj1 || [obj1 isEqualTo:obj2])
    {
    }

    if (!obj1 && ![obj1 isEqualTo:obj2])
    {
    }
}

BrokenNullCheck

Since: 0.7

The broken null check itself will crash the program.

This rule is defined by the following class: oclint-rules/rules/basic/BrokenNullCheckRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/basic/BrokenNullCheckRule.cpp]

Example:

void m(A *a, B *b)
{
    if (a != NULL || a->bar(b))
    {
    }

    if (a == NULL && a->bar(b))
    {
    }
}

BrokenOddnessCheck

Since: 0.6

Checking oddness by x % 2 == 1 won’t work for negative numbers. Use x & 1 == 1, or x % 2 != 0 instead.

This rule is defined by the following class: oclint-rules/rules/basic/BrokenOddnessCheckRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/basic/BrokenOddnessCheckRule.cpp]

Example:

void example()
{
    if (x % 2 == 1)         // violation
    {
    }

    if (foo() % 2 == 1)     // violation
    {
    }
}

CollapsibleIfStatements

Since: 0.6

This rule detects instances where the conditions of two consecutive if statements can combined into one in order to increase code cleanness and readability.

This rule is defined by the following class: oclint-rules/rules/basic/CollapsibleIfStatementsRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/basic/CollapsibleIfStatementsRule.cpp]

Example:

void example(bool x, bool y)
{
    if (x)              // these two if statements can be
    {
        if (y)          // combined to if (x && y)
        {
            foo();
        }
    }
}

ConstantConditionalOperator

Since: 0.6

conditional operator whose conditionals are always true or always false are confusing.

This rule is defined by the following class: oclint-rules/rules/basic/ConstantConditionalOperatorRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/basic/ConstantConditionalOperatorRule.cpp]

Example:

void example()
{
    int a = 1 == 1 ? 1 : 0;     // 1 == 1 is actually always true
}

ConstantIfExpression

Since: 0.2

if statements whose conditionals are always true or always false are confusing.

This rule is defined by the following class: oclint-rules/rules/basic/ConstantIfExpressionRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/basic/ConstantIfExpressionRule.cpp]

Example:

void example()
{
    if (true)       // always true
    {
        foo();
    }
    if (1 == 0)     // always false
    {
        bar();
    }
}

DeadCode

Since: 0.4

Code after return, break, continue, and throw statements are unreachable and will never be executed.

This rule is defined by the following class: oclint-rules/rules/basic/DeadCodeRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/basic/DeadCodeRule.cpp]

Example:

void example(id collection)
{
    for (id it in collection)
    {
        continue;
        int i1;                 // dead code
    }
    return;
    int i2;                     // dead code
}

DoubleNegative

Since: 0.6

There is no point in using a double negative, it is always positive.

This rule is defined by the following class: oclint-rules/rules/basic/DoubleNegativeRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/basic/DoubleNegativeRule.cpp]

Example:

void example()
{
    int b1 = !!1;
    int b2 = ~~1;
}

ForLoopShouldBeWhileLoop

Since: 0.6

Under certain circumstances, some for loops can be simplified to while loops to make code more concise.

This rule is defined by the following class: oclint-rules/rules/basic/ForLoopShouldBeWhileLoopRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/basic/ForLoopShouldBeWhileLoopRule.cpp]

Example:

void example(int a)
{
    for (; a < 100;)
    {
        foo(a);
    }
}

GotoStatement

Since: 0.6

“Go To Statement Considered Harmful” [http://www.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF]

This rule is defined by the following class: oclint-rules/rules/basic/GotoStatementRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/basic/GotoStatementRule.cpp]

Example:

void example()
{
    A:
        a();
    goto A;     // Considered Harmful, Considered Silly, Considered Stupid... ;)
}

References:

Edsger Dijkstra (March 1968). “Go To Statement Considered Harmful” [http://www.cs.utexas.edu/users/EWD/ewd02xx/EWD215.PDF]. Communications of the ACM (PDF) 11 (3): 147–148. doi:10.1145/362929.362947.

MisplacedNilCheck

Since: 0.7

The nil check is misplaced. In Objective-C, sending a message to a nil pointer simply does nothing. But code readers may be confused about the misplaced nil check.

This rule is defined by the following class: oclint-rules/rules/basic/MisplacedNullCheckRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/basic/MisplacedNullCheckRule.cpp]

Example:

+ (void)compare:(A *)obj1 withOther:(A *)obj2
{
    if ([obj1 isEqualTo:obj2] && obj1)
    {
    }

    if (![obj1 isEqualTo:obj2] || obj1 == nil)
    {
    }
}

MisplacedNullCheck

Since: 0.7

The null check is misplaced. In C and C++, sending a message to a null pointer could crash the app. When null is misplaced, either the check is useless or it’s incorrect.

This rule is defined by the following class: oclint-rules/rules/basic/MisplacedNullCheckRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/basic/MisplacedNullCheckRule.cpp]

Example:

void m(A *a, B *b)
{
    if (a->bar(b) && a != NULL) // violation
    {
    }

    if (a->bar(b) || !a)        // violation
    {
    }
}

MultipleUnaryOperator

Since: 0.6

Multiple unary operator can always be confusing and should be simplified.

This rule is defined by the following class: oclint-rules/rules/basic/MultipleUnaryOperatorRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/basic/MultipleUnaryOperatorRule.cpp]

Example:

void example()
{
    int b = -(+(!(~1)));
}

ReturnFromFinallyBlock

Since: 0.6

Returning from a finally block is not recommended.

This rule is defined by the following class: oclint-rules/rules/basic/ReturnFromFinallyBlockRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/basic/ReturnFromFinallyBlockRule.cpp]

Example:

void example()
{
    @try
    {
        foo();
    }
    @catch(id ex)
    {
        bar();
    }
    @finally
    {
        return;         // this can discard exceptions.
    }
}

ThrowExceptionFromFinallyBlock

Since: 0.6

Throwing exceptions within a finally block may mask other exceptions or code defects.

This rule is defined by the following class: oclint-rules/rules/basic/ThrowExceptionFromFinallyBlockRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/basic/ThrowExceptionFromFinallyBlockRule.cpp]

Example:

void example()
{
    @try {;}
    @catch(id ex) {;}
    @finally {
        id ex1;
        @throw ex1;                              // this throws an exception
        NSException *ex2 = [NSException new];
        [ex2 raise];                             // this throws an exception, too
    }
}

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Rule Index »

Convention

AvoidBranchingStatementAsLastInLoop

Since: 0.7

Having branching statement as the last statement inside a loop is very confusing, and could largely be forgetting of something and turning into a bug.

This rule is defined by the following class: oclint-rules/rules/convention/AvoidBranchingStatementAsLastInLoopRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/convention/AvoidBranchingStatementAsLastInLoopRule.cpp]

Example:

void example()
{
    for (int i = 0; i < 10; i++)
    {
        if (foo(i))
        {
            continue;
        }
        break;      // this break is confusing
    }
}

DefaultLabelNotLastInSwitchStatement

Since: 0.6

It is very confusing when default label is not the last label in a switch statement.

This rule is defined by the following class: oclint-rules/rules/convention/DefaultLabelNotLastInSwitchStatementRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/convention/DefaultLabelNotLastInSwitchStatementRule.cpp]

Example:

void example(int a)
{
    switch (a) {
        case 1:
            break;
        default:  // the default case should be last
            break;
        case 2:
            break;
    }
}

InvertedLogic

Since: 0.4

An inverted logic is hard to understand.

This rule is defined by the following class: oclint-rules/rules/convention/InvertedLogicRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/convention/InvertedLogicRule.cpp]

Example:

int example(int a)
{
    int i;
    if (a != 0)             // if (a == 0)
    {                       // {
        i = 1;              //      i = 0;
    }                       // }
    else                    // else
    {                       // {
        i = 0;              //      i = 1;
    }                       // }

    return !i ? -1 : 1;     // return i ? 1 : -1;
}

JumbledIncrementer

Since: 0.7

Jumbled incrementers are usually typos. If it’s done on purpose, it’s very confusing for code readers.

This rule is defined by the following class: oclint-rules/rules/convention/JumbledIncrementerRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/convention/JumbledIncrementerRule.cpp]

Example:

void example()
{
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 20; i++ /* what?! */)
        {
        }
    }
}

MissingBreakInSwitchStatement

Since: 0.6

A switch statement without a break statement has a very large chance to contribute a bug.

This rule is defined by the following class: oclint-rules/rules/convention/MissingBreakInSwitchStatement.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/convention/MissingBreakInSwitchStatement.cpp]

Example:

void example(int a)
{
    switch (a) {
        case 1:
            break;
        case 2:
            // do something
        default:
            break;
    }
}

NonCaseLabelInSwitchStatement

Since: 0.6

It is very confusing when default label is not the last label in a switch statement.

This rule is defined by the following class: oclint-rules/rules/convention/NonCaseLabelInSwitchStatementRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/convention/NonCaseLabelInSwitchStatementRule.cpp]

Example:

void example(int a)
{
    switch (a) {
        case 1:
            break;
        label1:     // label in a switch statement in really confusing
            break;
        default:
            break;
    }
}

ParameterReassignment

Since: 0.6

Reassigning values to parameters is very problematic in most cases.

This rule is defined by the following class: oclint-rules/rules/convention/ParameterReassignmentRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/convention/ParameterReassignmentRule.cpp]

Example:

void example(int a)
{
    if (a < 0)
    {
        a = 0; // reassign parameter a to 0
    }
}

SwitchStatementsShouldHaveDefault

Since: 0.6

Switch statements should a default statement.

This rule is defined by the following class: oclint-rules/rules/convention/SwitchStatementsShouldHaveDefaultRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/convention/SwitchStatementsShouldHaveDefaultRule.cpp]

Example:

void example(int a)
{
    switch (a) {
        case 1:
            break;
        case 2:
            break;
        // should have a default
    }
}

TooFewBranchesInSwitchStatement

Since: 0.6

To increase code readability, when a switch consists of only a few branches, it’s much better to use if statement.

This rule is defined by the following class: oclint-rules/rules/convention/TooFewBranchesInSwitchStatementRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/convention/TooFewBranchesInSwitchStatementRule.cpp]

Example:

void example(int a)
{
    switch (a) {
        case 1:
            break;
        default:
            break;
    } // Better to use an if statement and check if variable a equals 1.
}

Thresholds:

MINIMUM_CASES_IN_SWITCH

The reporting threshold for count of case statements in a switch statement, default value is 3

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Rule Index »

Empty

EmptyCatchStatement

Since: 0.6

This rule detects instances where an exception is caught, but nothing is done about it.

This rule is defined by the following class: oclint-rules/rules/empty/EmptyCatchStatementRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/empty/EmptyCatchStatementRule.cpp]

Example:

void example()
{
    try
    {
        int* m= new int[1000];
    }
    catch(...)                  // empty catch statement, this swallows an exception
    {
    }
}

EmptyDoWhileStatement

Since: 0.6

This rule detects instances where a do-while statement does nothing.

This rule is defined by the following class: oclint-rules/rules/empty/EmptyDoWhileStatementRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/empty/EmptyDoWhileStatementRule.cpp]

Example:

void example()
{
    do
    {                           // empty do-while statement
    } while(1);
}

EmptyElseBlock

Since: 0.6

This rule detects instances where a else statement does nothing.

This rule is defined by the following class: oclint-rules/rules/empty/EmptyElseStatementRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/empty/EmptyElseStatementRule.cpp]

Example:

int example(int a)
{
    if (1)
    {
        return a + 1;
    }
    else                // empty else statement, can be safely removed
    {
    }
}

EmptyFinallyStatement

Since: 0.6

This rule detects instances where a finally statement does nothing.

This rule is defined by the following class: oclint-rules/rules/empty/EmptyFinallyStatementRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/empty/EmptyFinallyStatementRule.cpp]

Example:

void example()
{
    Foo *foo;
    @try
    {
        [foo bar];
    }
    @catch(NSException *e)
    {
        NSLog(@"Exception occurred: %@", [e description]);
    }
    @finally            // empty finally statement, probably forget to clean up?
    {
    }
}

EmptyForStatement

Since: 0.6

This rule detects instances where a for statement does nothing.

This rule is defined by the following class: oclint-rules/rules/empty/EmptyForStatementRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/empty/EmptyForStatementRule.cpp]

Example:

void example(NSArray *array)
{
    for (;;)                // empty for statement
    {
    }

    for (id it in array)    // empty for-each statement
    {
    }
}

EmptyIfStatement

Since: 0.2

This rule detects instances where a condition is checked, but nothing is done about it.

This rule is defined by the following class: oclint-rules/rules/empty/EmptyIfStatementRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/empty/EmptyIfStatementRule.cpp]

Example:

void example(int a)
{
    if (a == 1)                  // empty if statement
    {
    }
}

EmptySwitchStatement

Since: 0.6

This rule detects instances where a switch statement does nothing.

This rule is defined by the following class: oclint-rules/rules/empty/EmptySwitchStatementRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/empty/EmptySwitchStatementRule.cpp]

Example:

void example(int i)
{
    switch (i)              // empty switch statement
    {
    }
}

EmptyTryStatement

Since: 0.6

This rule detects instances where a try statement is empty.

This rule is defined by the following class: oclint-rules/rules/empty/EmptyTryStatementRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/empty/EmptyTryStatementRule.cpp]

Example:

void example()
{
    try                     // but this try statement is empty
    {
    }
    catch(...)
    {
        cout << "Exception is caught!";
    }
}

EmptyWhileStatement

Since: 0.6

This rule detects instances where a while statement does nothing.

This rule is defined by the following class: oclint-rules/rules/empty/EmptyWhileStatementRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/empty/EmptyWhileStatementRule.cpp]

Example:

void example(int a)
{
    while(a--)              // empty while statement
    {
    }
}

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Rule Index »

Migration

ObjCBoxedExpressions

Since: 0.7

This rule locates the places that can be migrated to the new Objective-C literals with boxed expressions.

This rule is defined by the following class: oclint-rules/rules/migration/ObjCBoxedExpressionsRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/migration/ObjCBoxedExpressionsRule.cpp]

Example:

void aMethod()
{
    NSNumber *fortyTwo = [NSNumber numberWithInt:(43 - 1)];
    // NSNumber *fortyTwo = @(43 - 1);

    NSString *env = [NSString stringWithUTF8String:getenv("PATH")];
    // NSString *env = @(getenv("PATH"));
}

ObjCContainerLiterals

Since: 0.7

This rule locates the places that can be migrated to the new Objective-C literals with container literals.

This rule is defined by the following class: oclint-rules/rules/migration/ObjCContainerLiteralsRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/migration/ObjCContainerLiteralsRule.cpp]

Example:

void aMethod()
{
    NSArray *a = [NSArray arrayWithObjects:@1, @2, @3, nil];
    // NSArray *a = @[ @1, @2, @3 ];

    NSDictionary *d = [NSDictionary dictionaryWithObjects:@[@2,@4] forKeys:@[@1,@3]];
    // NSDictionary *d = @{ @1 : @2, @3 : @4 };
}

ObjCNSNumberLiterals

Since: 0.7

This rule locates the places that can be migrated to the new Objective-C literals with number literals.

This rule is defined by the following class: oclint-rules/rules/migration/ObjCNSNumberLiteralsRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/migration/ObjCNSNumberLiteralsRule.cpp]

Example:

void aMethod()
{
    NSNumber *fortyTwo = [NSNumber numberWithInt:42];
    // NSNumber *fortyTwo = @42;

    NSNumber *yesBool = [NSNumber numberWithBool:YES];
    // NSNumber *yesBool = @YES;
}

ObjCObjectSubscripting

Since: 0.7

This rule locates the places that can be migrated to the new Objective-C literals with object subscripting.

This rule is defined by the following class: oclint-rules/rules/migration/ObjCObjectSubscriptingRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/migration/ObjCObjectSubscriptingRule.cpp]

Example:

void aMethod(NSArray *a, NSDictionary *d)
{
    id item = [a objectAtIndex:0];
    // id item = a[0];

    id item = [d objectForKey:@1];
    // id item = d[@1];
}

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Rule Index »

Naming

LongVariableName

Since: 0.7

Variables with long names harm readability.

This rule is defined by the following class: oclint-rules/rules/naming/LongVariableNameRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/naming/LongVariableNameRule.cpp]

Example:

void aMethod()
{
    int reallyReallyLongIntegerName;
}

Thresholds:

LONG_VARIABLE_NAME

The long variable name reporting threshold, default value is 20

ShortVariableName

Since: 0.7

Variable with a short name is hard to understand what it stands for. Variable with name, but the name has number of characters less than the threshold will be emitted.

This rule is defined by the following class: oclint-rules/rules/naming/ShortVariableNameRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/naming/ShortVariableNameRule.cpp]

Example:

void aMethod(int i)  // i is short
{
    int ii;          // ii is short
}

Thresholds:

SHORT_VARIABLE_NAME

The short variable name reporting threshold, default value is 3

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Rule Index »

Redundant

RedundantConditionalOperator

Since: 0.6

This rule detects three types of redundant conditional operators:

true expression and false expression are returning true/false or false/true respectively;

true expression and false expression are the same constant;

true expression and false expression are the same variable expression.

They are usually introduced by mistake, and should be simplified.

This rule is defined by the following class: oclint-rules/rules/redundant/RedundantConditionalOperatorRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/redundant/RedundantConditionalOperatorRule.cpp]

Example:

void example(int a, int b, int c)
{
    bool b1 = a > b ? true : false;     // true/false: bool b1 = a > b;
    bool b2 = a > b ? false : true;     // false/true: bool b2 = !(a > b);
    int i1 = a > b ? 1 : 1;             // same constant: int i1 = 1;
    float f1 = a > b ? 1.0 : 1.00;      // equally constant: float f1 = 1.0;
    int i2 = a > b ? c : c;             // same variable: int i2 = c;
}

RedundantIfStatement

Since: 0.4

This rule detects unnecessary if statements.

This rule is defined by the following class: oclint-rules/rules/redundant/RedundantIfStatementRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/redundant/RedundantIfStatementRule.cpp]

Example:

bool example(int a, int b)
{
    if (a == b)             // this if statement is redundant
    {
        return true;
    }
    else
    {
        return false;
    }                       // the entire method can be simplified to return a == b;
}

RedundantLocalVariable

Since: 0.4

This rule detects cases where a variable declaration immediately followed by a return of that variable.

This rule is defined by the following class: oclint-rules/rules/redundant/RedundantLocalVariableRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/redundant/RedundantLocalVariableRule.cpp]

Example:

int example(int a)
{
    int b = a * 2;
    return b;   // variable b is returned immediately after its declaration,
}               // can be simplified to return a * 2;

RedundantNilCheck

Since: 0.7

C/C++-style null check in Objective-C like foo != nil && [foo bar] is redundant, since sending a message to a nil object in this case simply return a false-y value.

This rule is defined by the following class: oclint-rules/rules/redundant/RedundantLocalVariableRuleRedundantNilCheck.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/redundant/RedundantNilCheck.cpp]

Example:

+ (void)compare:(A *)obj1 withOther:(A *)obj2
{
    if (obj1 && [obj1 isEqualTo:obj2]) // if ([obj1 isEqualTo:obj2]) is okay
    {
    }
}

UnnecessaryElseStatement

Since: 0.6

When an if statement block ends with a return statement, or all branches in the if statement block end with return statements, then the else statement is unnecessary. The code in the else statement can be run without being in the block.

This rule is defined by the following class: oclint-rules/rules/redundant/UnnecessaryElseStatementRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/redundant/UnnecessaryElseStatementRule.cpp]

Example:

bool example(int a)
{
    if (a == 1)                 // if (a == 1)
    {                           // {
        cout << "a is 1.";      //     cout << "a is 1.";
        return true;            //     return true;
    }                           // }
    else                        //
    {                           //
        cout << "a is not 1."   // cout << "a is not 1."
    }                           //
}

UselessParentheses

Since: 0.6

This rule detects useless parentheses.

This rule is defined by the following class: oclint-rules/rules/redundant/UselessParenthesesRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/redundant/UselessParenthesesRule.cpp]

Example:

int example(int a)
{
    int y = (a + 1);    // int y = a + 1;
    if ((y > 0))        // if (y > 0)
    {
        return a;
    }
    return (0);         // return 0;
}

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Rule Index »

Size

CyclomaticComplexity

Since: 0.4

Cyclomatic complexity is determined by the number of linearly independent paths through a program’s source code. In other words, cyclomatic complexity of a method is measured by the number of decision points, like if, while, and for statements, plus one for the method entry.

The experiments McCabe, the author of cyclomatic complexity, conclude that methods in the 3 to 7 complexity range are quite well structured. He also suggest the cyclomatic complexity of 10 is a reasonable upper limit.

This rule is defined by the following class: oclint-rules/rules/size/CyclomaticComplexityRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/size/CyclomaticComplexityRule.cpp]

Example:

void example(int a, int b, int c) // 1
{
    if (a == b)                   // 2
    {
        if (b == c)               // 3
        {
        }
        else if (a == c)          // 3
        {
        }
        else
        {
        }
    }
    for (int i = 0; i < c; i++)   // 4
    {
    }
    switch(c)
    {
        case 1:                   // 5
            break;
        case 2:                   // 6
            break;
        default:                  // 7
            break;
    }
}

Thresholds:

CYCLOMATIC_COMPLEXITY

The cyclomatic complexity reporting threshold, default value is 10

Suppress:

__attribute__((annotate("oclint:suppress[high cyclomatic complexity]")))

References:

McCabe (December 1976). “A Complexity Measure” [http://www.literateprogramming.com/mccabe.pdf]. IEEE Transactions on Software Engineering: 308–320

LongClass

Since: 0.6

Long class generally indicates that this class tries to so many things. Each class should do one thing and one thing well.

This rule is defined by the following class: oclint-rules/rules/size/LongClassRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/size/LongClassRule.cpp]

Example:

class Foo
{
    void bar()
    {
        // 1001 lines of code
    }
}

Thresholds:

LONG_CLASS

The class size reporting threshold, default value is 1000

LongLine

Since: 0.6

When number of characters for one line of code is very long, it largely harm the readability. Break long line of code into multiple lines.

This rule is defined by the following class: oclint-rules/rules/size/LongLineRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/size/LongLineRule.cpp]

Example:

void example()
{
    int a012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789;
}

Thresholds:

LONG_LINE

The long line reporting threshold, default value is 100

LongMethod

Since: 0.4

Long method generally indicates that this method tries to so many things. Each method should do one thing and one thing well.

This rule is defined by the following class: oclint-rules/rules/size/LongMethodRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/size/LongMethodRule.cpp]

Example:

void example()
{
    cout << "hello world";
    cout << "hello world";
    // repeat 48 times
}

Thresholds:

LONG_METHOD

The long method reporting threshold, default value is 50

NcssMethodCount

Since: 0.6

This rule counts number of lines for a method by counting Non Commenting Source Statements (NCSS). NCSS only takes actual statements into consideration, in other words, ignores empty statements, empty blocks, closing brackets or semicolons after closing brackets. Meanwhile, statement that is break into multiple lines contribute only one count.

This rule is defined by the following class: oclint-rules/rules/size/NcssMethodCountRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/size/NcssMethodCountRule.cpp]

Example:

void example()          // 1
{
    if (1)              // 2
    {
    }
    else                // 3
    {
    }
}

Thresholds:

NCSS_METHOD

The high NCSS method reporting threshold, default value is 30

Suppress:

__attribute__((annotate("oclint:suppress[high ncss method]")))

NestedBlockDepth

Since: 0.6

This rule indicates blocks nested more deeply than the upper limit.

This rule is defined by the following class: oclint-rules/rules/size/NestedBlockDepthRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/size/NestedBlockDepthRule.cpp]

Example:

if (1)
{               // 1
    {           // 2
        {       // 3
        }
    }
}

Thresholds:

NESTED_BLOCK_DEPTH

The depth of a block or compound statement reporting threshold, default value is 5

NPathComplexity

Since: 0.4

NPath complexity is determined by the number of execution paths through that method. Compared to cyclomatic complexity, NPath complexity has two outstanding characteristics: first, it distinguish between different kinds of control flow structures; second, it takes the various type of acyclic paths in a flow graph into consideration.

Based on studies done by the original author in AT&T Bell Lab, an NPath threshold value of 200 has been established for a method.

This rule is defined by the following class: oclint-rules/rules/size/NPathComplexityRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/size/NPathComplexityRule.cpp]

Example:

void example()
{
    // complicated code that is hard to understand
}

Thresholds:

NPATH_COMPLEXITY

The NPath complexity reporting threshold, default value is 200

Suppress:

__attribute__((annotate("oclint:suppress[high npath complexity]")))

References:

Brian A. Nejmeh (1988). “NPATH: a measure of execution path complexity and its applications” [http://dl.acm.org/citation.cfm?id=42379]. Communications of the ACM 31 (2) p. 188-200

TooManyFields

Since: 0.7

A class with too many fields indicates it does too many things and is lack of proper abstraction. It can be resigned to have fewer fields.

This rule is defined by the following class: oclint-rules/rules/size/TooManyFieldsRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/size/TooManyFieldsRule.cpp]

Example:

class c
{
    int a, b;
    int c;
    // ...
    int l;
    int m, n;
    // ...
    int x, y, z;

    void m() {}
};

Thresholds:

TOO_MANY_FIELDS

The reporting threshold for too many fields, default value is 20

TooManyMethods

Since: 0.7

A class with too many methods indicates it does too many things and hard to read and understand. It usually contains complicated code, and should be refactored.

This rule is defined by the following class: oclint-rules/rules/size/TooManyMethodsRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/size/TooManyMethodsRule.cpp]

Example:

class c
{
    int a();
    int b();
    int c();
    // ...
    int l();
    int m();
    int n();
    // ...
    int x();
    int y();
    int z();
    int aa();
    int ab();
    int ac();
    int ad();
    int ae();
};

Thresholds:

TOO_MANY_METHODS

The reporting threshold for too many methods, default value is 30

TooManyParameters

Since: 0.7

Methods with too many parameters are hard to understand and maintain, and are thirsty for refactorings, like Replace Parameter With method [http://www.refactoring.com/catalog/replaceParameterWithMethod.html], Introduce Parameter Object [http://www.refactoring.com/catalog/introduceParameterObject.html], or Preserve Whole Object [http://www.refactoring.com/catalog/preserveWholeObject.html].

This rule is defined by the following class: oclint-rules/rules/size/TooManyParametersRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/size/TooManyParametersRule.cpp]

Example:

void example(int a, int b, int c, int d, int e, int f,
    int g, int h, int i, int j, int k, int l)
{
}

Thresholds:

TOO_MANY_PARAMETERS

The reporting threshold for too many parameters, default value is 10

References:

Fowler, Martin (1999). Refactoring: Improving the design of existing code. Addison Wesley.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Rule Index »

Unused

UnusedLocalVariable

Since: 0.4

This rule detects local variables that are declared, but not used.

This rule is defined by the following class: oclint-rules/rules/unused/UnusedLocalVariableRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/unused/UnusedLocalVariableRule.cpp]

Example:

int example(int a)
{
    int i;          // variable i is declared, but not used
    return 0;
}

Suppress:

__attribute__((annotate("oclint:suppress[unused local variable]")))

UnusedMethodParameter

Since: 0.4

This rule detects parameters that are not used in the method.

This rule is defined by the following class: oclint-rules/rules/unused/UnusedMethodParameterRule.cpp [https://github.com/oclint/oclint/blob/master/oclint-rules/rules/unused/UnusedMethodParameterRule.cpp]

Example:

int example(int a)  // parameter a is not used
{
    return 0;
}

Suppress:

__attribute__((annotate("oclint:suppress[unused method parameter]")))

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

OCLint Internals

Core Module

Metrics Module

Cyclomatic Complexity

NPath Complexity

Non Commenting Source Statements

Statement Depth

Rules Module

Reporters Module

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

OCLint Internals »

Core Module

Core module is the engine of OCLint. In general, it dispatches the tasks to other modules in order, drives the work flow of the entire analysis process, and generates outputs.

When OCLint is invoked, it reads the source code files and parses them into abstract syntax tree (AST), it also loads rules and chosen reporter.

Rules then analyze deeply into each AST representation of the source code, and find smelly AST nodes that match the predefined patterns.

During the inspection, certain metrics are calculated to have a better understanding of the source code. In addition, some rules ask for threshold configurations in order to decide whether to emit violations.

All violations are collected into a set, and are eventually sent to the reporter. Selected reporter will then convert violation set and related statistic summarization into certain type of report for output.

Following is a brief description of each component in the core module:

CommandLineOptions

Extends command line arguments on top of LibTooling and defines new options for OCLint.

Processor

Takes over ASTContext, initializes ViolationSet and RuleCarrier, and then applies all loaded rules for analysis, finally, pushes the ViolationSet into Results.

Reporter

Defines the interface of all reporters.

Results

Is essentially a collection of ViolationSet. Plus some methods to find statistic results inside all violations.

RuleBase

Defines the base interface of all rules.

RuleCarrier

As its name implies, it carries the AST of the source code and a violation set. When it is initialized in Processor, it takes an immutable AST context and an empty violation set. Then, it is examined through all rules. Each rule traverses the AST context and focus on a specific aspect. When it finds a matched pattern, a violation will be pushed to violation set. Eventually, a contaminated RuleVarrier will return back with all violations for diagnostic.

RuleConfiguration

Statically stores custom thresholds for rules.

RuleSet

When selected rules are loaded, they are collected into this RuleSet.

Version

Contains the current version identifier, can be used in places, like reporters, where version is a differentiator.

Violation

Is a container of all details about a violation, like the violated rule, path of the source code, start line and column number, end line and column number, and sometimes, a helper diagnostic message or suggestion.

ViolationSet

Is a collection of violations.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

OCLint Internals »

Metrics Module

Metrics module is an isolated library. THis module actually doesn’t depend on any other OCLint modules. It means we can use this module separately in other projects that also measure the metrics of the source code.

Cyclomatic Complexity

Cyclomatic complexity was introduced by Thomas McCabe. It is determined based on the number of decision points in a method.

NPath Complexity

NPath complexity measures the number of acyclic execution paths in a method. It differs from cyclomatic complexity as it takes into account the nesting of conditional statements and multi-part boolean expressions.

Non Commenting Source Statements

Non commeting source statements (NCSS) counts the number of all statements excluding comments, empty statements, empty blocks, closing brackets or semicolons after closing brackets.

Statement Depth

Statement depth is the number of nesting levels.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

OCLint Internals »

Rules Module

OCLint is a rule based tools. Rules are dynamic libraries that can be easily loaded into system during runtime. It largely makes the tool very extensible. In addition, by following Open/Close Principle [http://en.wikipedia.org/wiki/Open/closed_principle], OCLint is very open to new rules by dynamically loading extended rules without modifying or recompiling itself,

All the rules are implemented as a subclass of RuleBase. They generally fall in two big categories - rules by reading the source code line by line, and the ones by recognizing patterns in the abstract syntax tree (AST).

Rules that belong to the first category can leverage the abstract class AbstractSourceCodeReaderRule to go through each line of the source code.

For rules that are interested in AST, we provide two detail approaches - AST visitor and AST matcher.

In AST visitor approach, by following the Visitor Pattern [http://en.wikipedia.org/wiki/Visitor_pattern], the entire AST is traversed recursively from the root of the tree. Each node is visited in a depth-first preorder traversal [http://en.wikipedia.org/wiki/Tree_traversal]. The visitor usually returns after all nodes are visited. However, we can interrupt the traversal by intent, for example, when we are only curious about if certain patterns exist rather than how many of them, in this case, whenever that pattern is matched, we could stop the visitor to avoid wasting more resources, so that the performance can be improved.

Tree traversal is very mature and powerful, we can achieve almost everything with it. But it’s not that intuitive to some extents. So, AST matcher, on the other hand, can help write lightweight code with better readability.

The way to think about AST matcher to AST is like XPath to XML. Specific patterns in AST are described in a simple, concise, and descriptive representation. Although it’s implemented by AST visitor under the hook, the matcher expression makes it more friendly when people who read the code try to understand what the rule actually does. For example, in order to find an if statement, we can simple write our matcher like

ifStmt()

When we want to narrow our search criteria for a particular group of if statements, let’s say, a if statement with a binary operator that compares if two variables are equal, then we can extend the above matcher to

ifStmt(hasCondition(binaryOperator(hasOperatorName("&&"))))

It can be read just like a sentence.

Using AST matchers has more restrictions than AST visitor, and it takes much longer time in analysis, this could lower the performance of the tool. So, we always have to consider the trade-off, and choose wisely.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

OCLint Internals »

Reporters Module

After the analysis process, for each of the violations detected, we know the detail information of the node, the rule, and sometimes the diagnostic message. Reporters will take the information, and convert them into human readable reporters.

Note

In some cases, the outputs are not directly readable for people, instead they will be rendered by other tools for better representations. For example, continuous integration systems can understand a specific type of output, and convert it into graphic interface on its dashboard.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Development

System Requirements

LLVM System Requirements

OCLint System Requirements

Extra Notes

Checking Out Code

OCLint GitHub Repositories

LLVM/Clang Codebase

googltest/googlemock

Summary

Compiling and Testing

Building LLVM/Clang

Building googletest/googlemock

Compiling and Testing OCLint

Writing Custom Rules

Generic Rules

Source Code Reader Rules

AST Visitor Rules

AST Matcher Rules

Creating Rules with Scaffolding

Build it and Make it Live

Unit Testing

Writing Custom Reporters

Scaffolding

Creating Rules with Scaffolding

Creating Reporters with Scaffolding

Eating Your Own Dog Food

Requirements

Dogfooding

Open Projects

More Rules

More Reporters

More Metrics

Better Build System

Package Manager Build

Xcode Plugin/Addon/Extension

Control Flow Graphic Engine

Data Flow Engine

Code Duplication and Logic Duplication Detection

Refactoring Suggestions

Design Patterns Extraction

Type Inference

Related Clang Knowledge Base

LibTooling

Clang AST

LibASTMatchers

Coding Standards

Naming Convention

Use Spaces Instead of Tabs

Treat Compiler Warnings Like Errors

Don’t Use else after return

Don’t Use Inverted Logic

No States in Rules

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Development »

System Requirements

OCLint can be compiled on all unix-like systems, theoretically. Latest Mac OS X, FreeBSD, and major Linux distributions are tested and recommended.

LLVM System Requirements

OCLint is based on libTooling [http://clang.llvm.org/docs/LibTooling.html] for parsing source code and generating Abstract Syntax Tree [http://en.wikipedia.org/wiki/Abstract_syntax_tree] (AST) generation. Prior to compiling OCLint, we need to compile LLVM/Clang. Check out LLVM System Requirements [http://llvm.org/docs/GettingStarted.html#requirements] for requirements. These requirements are very fundamental development tools that probably you already have them.

OCLint System Requirements

Some tools are emphasized here, you may want to double check and make sure the toolkit is ready when you need it.

Apache Subversion [http://subversion.apache.org/]

Git [http://git-scm.com/]

CMake [http://www.cmake.org/]

LTP GCOV Extension [http://ltp.sourceforge.net/coverage/lcov.php] (lcov)

Extra Notes

Notes for Mac OS X

Homebrew [http://mxcl.github.com/homebrew/] is highly recommended for Mac OS X users. When we have homebrew installed, we can simply get all the dependencies by

brew install subversion git cmake lcov

Notes for Ubuntu

All Ubuntu users should be able to get all the dependencies by apt-get, for example:

apt-get install subversion git cmake lcov

We have noticed the coverage meta data generated by clang is not compatible with the latest version of gcov, but a gcov 4.2, 4.3 and 4.4 versions should work. In order to get the code coverage report, downgrading entire gcc tool set is recommended. Ubuntu provides a handy method to keep multiple versions in the system and easy to switch among them by update-alternatives, for example:

apt-get install g++-4.4
update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-4.6 10
update-alternatives --install /usr/bin/gcov gcov /usr/bin/gcov-4.4 20
update-alternatives --config gcov # and choose version 4.4
# you can also use the same method to switch your gcc and g++ compiler, but it's optional

Notes for Fedora

We should be able to get all the dependencies by yum, for example:

yum install gcc-c++ make git subversion cmake lcov

Notes for FreeBSD

The dependencies can be found in the follow ports folders:

/usr/ports/devel/subversion16

LLVM codebase is not compatible with 1.7 version yet

/usr/ports/devel/git

/usr/ports/devel/cmake

/usr/ports/devel/lcov

Simply go through each folder, and install them by

make install clean

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Development »

Checking Out Code

This document helps get the latest source code of OCLint, its submodules and dependencies. We will also describe the preferred structure of your codebase in this document.

Note

There is a summary of necessary terminal commands at the bottom of this document, here is the free ride for skipping all the detail and going directly to there.

OCLint GitHub Repositories

All source code of OCLint and its submodules are hosted at GitHub [https://github.com/oclint].

oclint/oclint

This repository hosts the OCLint source code, which consists of core, metrics, rules, and reporters modules. Check out the code by

git clone https://github.com/oclint/oclint.git

It will create a oclint folder in current directory, let’s give it an alias name OCLINT_HOME.

oclint/oclint-json-compilation-database

This repository contains the Python code for oclint-json-compilation-database.

Go into the OCLINT_HOME folder, and check out this repository in there:

git clone https://github.com/oclint/oclint-json-compilation-database.git

oclint/oclint-xcodebuild

Code for ocling-xcodebuild has been pushed to this repository. Go to the OCLINT_HOME folder, and check out the code:

git clone https://github.com/oclint/oclint-xcodebuild.git

Note

oclint/oclint is pretty much everything you need if you are interested in OCLint development. The other two helper programs support OCLint to ease developers in certain ways. They are standalone programs themselves. Check out them when you want to improve them or you are willing to use the development version OCLint in your environment. Also, in order to run dogfooding, you still need to checkout oclint/oclint-json-compilation-database.

LLVM/Clang Codebase

LLVM/Clang has its own code structure, and the detail information can be found at Clang’s Get Started [http://clang.llvm.org/get_started.html] page. We also provide a script that checks out all LLVM/Clang repositories into correct location.

cd oclint-scripts
./checkoutLLVMClang.sh tags/RELEASE_33/final
cd ..

In addition, checkoutLLVMClang.sh script does more than that:

First, ./checkoutLLVMClang.sh update can update the existing LLVM/Clang checkout.

Second, you can check out a branch codebase other than the trunk codebase by ./checkoutLLVMClang.sh <branch_name>

We can find the current supported list of branches by ./checkoutLLVMClang.sh branch.

googltest/googlemock

Google C++ Testing and Mocking Frameworks are used for testing OCLint. OCLint follows Test Driven Development [http://en.wikipedia.org/wiki/Test-driven_development] (TDD), so checkout them before we work on this codebase and want to make sure the modifications do not break the other pieces of code.

We also provide a script checkoutGoogleTest.sh with two functions:

Check out the code simply by ./checkoutGoogleTest.sh

Update the codebase by ./checkoutGoogleTest.sh update

Summary

Sum up, to check out all OCLint modules and dependencies, we could execute the following commands:

git clone https://github.com/oclint/oclint.git
cd oclint
git clone https://github.com/oclint/oclint-json-compilation-database.git
git clone https://github.com/oclint/oclint-xcodebuild.git
cd oclint-scripts
./checkoutLLVMClang.sh
./checkoutGoogleTest.sh
cd .. # back to the root folder of OCLint codebase

To update the entire codebase, we can do:

cd oclint # start from OCLint root directory
git pull origin master
cd oclint-json-compilation-database
git pull origin master
cd ../oclint-xcodebuild
git pull origin master
cd ../oclint-scripts
./checkoutLLVMClang.sh update
./checkoutGoogleTest.sh update
cd .. # back to OCLint root directory

So now, we OCLint directory might be like this:

oclint
|-README
|-build
|-googletest
|-llvm
|-oclint-clang-plugin
|-oclint-clang-tooling
|-oclint-core
|---include
|---lib
|---test
|-oclint-json-compilation-database
|-oclint-metrics
|---include
|---lib
|---test
|-oclint-rules
|---include
|---lib
|---rules
|---template
|---test
|-oclint-reporters
|---reporters
|---template
|---test
|-oclint-scripts
|-oclint-xcodebuild

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Development »

Compiling and Testing

We will go through some steps to build dependencies, compile and test OCLint in this document. In general, if you have followed the codebase structure as described in this document, we have scripts to gather all required steps and run them in order to facilitate the entire process.

Warning

if you need a release version OCLint binary for production use, please read Building OCLint instead.

Note

This document presumes your current working directory is oclint/oclint-scripts.

Building LLVM/Clang

We could build LLVM/Clang in debug mode with assertions by

./buildClang.sh

Debug mode binaries contain additional data to aid debugging, but lowers program performances. It’s recommended to build Clang in debug mode when we work on the analysis engine, metrics, and rules. These debug information may help a lot in some circumstances.

On the other side, if our work is related to violations, reporters, and surrounding submodules, we can still use debug mode, and we can also choose release mode that enables optimizations for better performance. To build LLVM/Clang in release mode, append release to the script as

./buildClang.sh release

It takes a while to build LLVM/Clang (probably longer than a cup of coffee time). We can specify make -j <number_of_jobs> to compile simultaneously.

The LLVM/Clang build can be found at oclint/build/llvm directory, and its installation is located at oclint/build/llvm-install folder.

Building googletest/googlemock

Building Google C++ Testing and Mocking Frameworks is easy:

./buildGoogleTest.sh

Compiling and Testing OCLint

OCLint uses CMake as build system. We can find CMakeLists.txt in each module and its include sub-folders.

There are four scripts, testCore.sh, testMetrics.sh, testRules.sh, and testReporters.sh for compiling and testing OCLint core module, metrics module, rules module, and reporters module respectively. Core module and metrics module can be compiled independently. However, rules module depends on both core and metrics modules, and reporters module depends on core module.

Each script has a clean option to remove old build intermediate files.

Scripts will show the CMake configuration process, compilation progress, and test results in order. testCore.sh will generate code coverage report in the end. When something goes wrong, scripts stop immediately with the following return code:

1 - CMake configuration failed

2 - Build failed

3 - Test failed

4 - Code coverage failed (for core module only)

Testing Core Module

Test core module:

./testCore.sh

Test core module with clean build:

./testCore.sh clean

In addition to the test results, code coverage report can be found in oclint/build/oclint-core-test/coveragereport folder. Please read the report by opening index.html with your browser.

Testing Metrics Module

Test metrics module:

./testMetrics.sh

Test metrics module with clean build:

./testMetrics clean

Testing Rules Module

Test rules module:

./testRules.sh

Test rules module with clean build:

./testRules.sh clean

Testing Reporters Module

Test reporters module:

./testReporters.sh

Test reporters module with clean build:

./testReporters.sh clean

Reviewing Test Results

We could always go back and review our test results (unless we have cleaned test directory with clean option or delete that folder manually). There is an easy way to do it with showTestResults.sh script. It uses less utility to display the test results on terminal.

By default, it shows the test results for core module. We can also explicitly specify core as an option to it, like

./showTestResults.sh
./showTestResults.sh core

Show test results for metrics module:

./showTestResults.sh metrics

Show test results for rules module:

./showTestResults.sh rules

Show test results for reporters module:

./showTestResults.sh reporters

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Development »

Writing Custom Rules

It’s cool to add capability to OCLint by writing your own rules, instead of waiting for us get around to implementing them. You are more welcome to share your rules with the entire community.

Note

It might be easier to get started with looking at existing rules.

Rules must implement RuleBase class or its derived abstract classes. Different rules are specialized in different abstract levels, for example, some rules may have to dig very deep into the control flow of the code, and on the contrary, some rules only detect the defects by reading the string of the source code. Rules module internals can help pick up the right category when writing rules. Here, we skip that discussion, and directly jump to these different types of rules.

Generic Rules

Writing a generic rule, we need to implement RuleBase interface.

We name the new rule and set the priority to it. Name will be shown in the report along with the violations. Priority stands for how severe when something breaks the rule. Priorities are defined in number, the less number has a higher priority, meaning, people needs to pay more attention to them.

RuleBase only provides a RuleCarrier, which carries the context of the abstract syntax tree (ASTContext) and a violation set. The ASTContext already have all syntactic information we need for analysis, and we need to figure out the way ourselves. We write our logic in apply method.

When we find the nodes we need in the ASTContext, throw those nodes into the violation set inside RuleCarrier.

For all rules, we use static constructor to register the rules. A static attribute is a variable that has been allocated statically, the lifetime of static variable extends across the entire execution of the program. So, each rule implementation has a static member rules, and we need to make sure our rule can be collected by it when being loaded.

Writing generic rules is very flexible, we can do everything we want from the ASTContext we have. However, since the most of our rules can reuse certain logic to have the work done better, so we recommend the new rules inherent from the abstract classes described below instead of using RuleBase directly. Don’t worry of losing the flexibility, all abstract classes are subclasses of RuleBase, so when we need this type of flexibility, we can still have it.

In addition, certain methods are still pure in these abstract classes, like name and priority methods. Plus the static RuleSet constructor, we still need to implement them in all rules. [Thinking about the paragraph to make it goes smotthier to the next paragraph.] Now, let’s look at some abstract rule classes.

Source Code Reader Rules

AbstractSourceCodeReaderRule provides a eachLine method. We can have the text of each line and the current line number. We can then work around with the text. For example, we can calculate the length of the text, we can understand if it is a comment, we can find out if there is a mix use of spaces and tabs, and so on.

AST Visitor Rules

The majority of the existing rules inherit AbstractASTVisitorRule class. It follows the visitor pattern [http://en.wikipedia.org/wiki/Visitor_pattern]. In our rules, we only write methods for the type of nodes that we are interested. For example, when we want to inspect all if statement, we should write

bool VisitIfStmt(IfStmt *ifStmt)
{
    // do stuff with this if statement
    return true;
}

Similarly, when we analyze an Objective-C method, we can visit that node by

bool VisitObjCMethodDecl(ObjCMethodDecl *decl)
{
    // analyze decl
    return false;
}

The return boolean value of these visit methods are used to control the traversal. AST visitor will continue its sub nodes or sibling nodes when visiting the current node return a true, vice versa, it stops when current visit method returns a false.

See also

We are using the abstract syntax tree generated by Clang, so understanding the API of Clang AST is very helpful when writing rules. There are some useful links that we have assembled together in Related Clang Knowledge Base page.

We also have a setUp method and a tearDown method in case we need to prepare certain stuff ready before the analysis and wrap up results afterwards. setUp method is guaranteed to be called before visiting any of the AST nodes, and after the AST analysis is done, tearDown is called for sure.

AST Matcher Rules

If possible, we are more willing to write AST matcher rules (unless performance is a big issue), in order to achieve the great readability that comes along with the AST matcher. We always prefer simple and concise.

All AST matcher rules inherit from AbstractASTMatcherRule class.

We need to add all matchers in setUpMatcher method. With each matcher, we bind a unique (within the scope of current rule) name for that in matcher.

Then whenever a match is found, callback method is called with that AST node as a parameter. So we can get that node with the name we have binded in previous step. We then add this node with other information into violation set.

See also

Again, LibASTMatcher is provided by Clang, and we would like to suggest you by reading some related Clang knowledge to have a better understanding.

Creating Rules with Scaffolding

Rules scaffolding is a quick way to create custom rules. When we want to create our custom rules and build them along with the OCLint building pipeline, scaffolding is the tool for the job.

We can tell the category, rule type, name, and priority to the scaffold script, or we can leave them with default settings.

Read on rule scaffolding document for details.

Build it and Make it Live

After coding for our new rule, now we have our new rule ready. We need to compile it into a dynamic library and link against LLVMSupport, clangASTMatchers, OCLintMetric, OCLintUtil, and OCLintCore libraries. We also have a CMake macro build_dynamic_rule to ease this process.

We copy the new dynamic library into $(/path/to/bin/oclint)/../lib/oclint/rules, and it will be loaded together with all other rules in this folder.

Unit Testing

We have a series of convenient methods for rules’ unit testing. They are testRuleOnCode method for regular C code, testRuleOnCXXCode method for C++ code, and testRuleOnObjCCode method to test Objective-C code. By giving the code we want to apply the rule on and our expectation result, this method will parse the code and run only current rule, and compare the expectation. It fails the test when the rule doesn’t meet expecting behaviors. A quick sample usage is like this

TEST(BitwiseOperatorInConditionalRuleTest, BitwiseOrInWhile)
{
    testRuleOnCode(new BitwiseOperatorInConditionalRule(), "void m() { while (1 | 0) {;} }", 0, 1, 19, 1, 23);
    // testRuleOnCode(
    //     new RuleToBeTested(),
    //     "source code",
    //     violationIndex,
    //     expectStartLine,
    //     expectStartColumn,
    //     expectEndLine,
    //     expectEndColumn,
    //     optionalExpectMessage);
    // When we expect the code has no violation, simple write
    // testRuleOnCode(new RuleToBeTested(), "source code");
}

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Development »

Writing Custom Reporters

Currently we have multiple types of reporters, like plain text and HTML. To enable extended capabilities, custom reporters are easily implemented for your own supports.

We have a oclint-reporters module, and all reporters are recommended to add to this module.

New reporters need to inherit Reporter interface. We will implement two methods that are required by the interface.

First of all, give the new reporter an identifier in name method. Then give the same name with -report-type option to oclint main program in order to use this new reporter later.

Then implement logic in report method. We have a outstream as a output stream on hand. In addition, all the information the new reporter needs is in the Results class.

Lastly, there is one small extra effort that is not defined in the interface, but is required when OCLint tries to load this reporter. Please copy and paste the code below, and replace YourNewReporter with your class name.

extern "C" Reporter* create()
{
  return new YourNewReporter();
}

That’s it. Now compile your new reporter and link it against OCLintCore library into a new dynamic library. We have a CMake macro BUILD_DYNAMIC_REPORTER to make this part easier.

See also

Reporter scaffolding is the tool for accelerating this process, it helps create the reporter source code from template and corresponding build configurations. As developers, we only need to think about the logic of rendering results.

Put the generated dynamic library into $(/path/to/bin/oclint)/../lib/oclint/reporters along with other reporter libraries. Done!

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Development »

Scaffolding

Rules and reporters classes are designed by contract, meaning they need to inherit their base classes, and implement pure virtual methods, and their source code follow certain structures. So we could scaffold new rules and reporters by copying their templates and replacing the placeholders. In addition, the scaffolding scripts can ease your work by adding the new rule and reporter to the OCLint build pipeline.

This document provides information on how to create rules and reporters with scaffold scripts.

Creating Rules with Scaffolding

Creating a custom rule can be done with scaffoldRule.py script under oclint-scripts folder.

We could get a list of its options by typing ./scaffoldRule.py -h:

usage: scaffoldRule.py [-h]
                       [-t {Generic,SourceCodeReader,ASTVisitor,ASTMatcher}]
                       [-c RULE_CATEGORY] [-n RULE_NAME] [-p {1,2,3}]
                       class_name

positional arguments:
  class_name            class name of the rule

optional arguments:
  -h, --help            show this help message and exit
  -t {Generic,SourceCodeReader,ASTVisitor,ASTMatcher}, --type {Generic,SourceCodeReader,ASTVisitor,ASTMatcher}
  -c RULE_CATEGORY, --category RULE_CATEGORY
  -n RULE_NAME, --name RULE_NAME
  -p {1,2,3}, --priority {1,2,3}

From where, we could specify the class name, along with the name, type, category and priority of the rule.

Class name is the only required argument. Without explicitly given a rule name, it could be generated according to the class name. The default values of type, category and priority are Generic, custom and 3 respectively.

See also

Learn how to choose the proper rule interface from Rule Module Internals document.

For example, if we want to create a controversial rule that extracts all switch statements with abstract syntax tree (AST) matcher, we can enter this command in the terminal:

./scaffoldRule.py AllSwitchStatements -c controversial -t ASTMatcher

Notice we would like scaffold script to populate the rule name and assign the default priority to this rule for us.

The scaffold script will create AllSwitchStatementsRule.cpp file, and store it in controversial folder under oclint-rules/rules. The rule will be generated like the following:

#include "oclint/AbstractASTMatcherRule.h"
#include "oclint/RuleSet.h"

class AllSwitchStatementsRule : public AbstractASTMatcherRule
{

private:
    static RuleSet rules;

public:
    virtual const string name() const
    {
        return "all switch statements";
    }

    virtual int priority() const
    {
        return 3;
    }

    virtual void callback(const MatchFinder::MatchResult &result)
    {
    }

    virtual void setUpMatcher()
    {
    }

};

RuleSet AllSwitchStatementsRule::rules(new AllSwitchStatementsRule());

In addition, related CMakeLists.txt files will be edited to ensure the new rule will be built along with other existing rules.

Now, the scaffolding is finished, we can refer to Writing Custom Rules document to fill in the logic for the rule.

Creating Reporters with Scaffolding

Scaffolding a reporter is very similar to the rule, but much easier, since it only requires the reporter’s class name with an optional argument for specifying the reporter’s name. We could also get these options by typing ./scaffoldReporter.py -h:

usage: scaffoldReporter.py [-h] [-n REPORTER_NAME] class_name

positional arguments:
  class_name            class name of the reporter

optional arguments:
  -h, --help            show this help message and exit
  -n REPORTER_NAME, --name REPORTER_NAME

Let’s say we want to create a new ColorfulTextReporter, with this script, we could do

./scaffoldReporter.py ColorfulText -n color

The generated ColorfulTextReporter.cpp will look like the following:

#include "oclint/Reporter.h"

class ColorfulTextReporter : public Reporter
{
public:
    virtual const string name() const
    {
        return "color";
    }

    virtual void report(Results *results, ostream &out)
    {
    }
};

extern "C" Reporter* create()
{
  return new ColorfulTextReporter();
}

Sequentially, the CMakeLists.txt file under reporters folder will be edited by appending the new reporter.

Now, we can refer to the Writing Custom Reporters document to print out the analysis results.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Development »

Eating Your Own Dog Food

OCLint, being a static code analysis tool that helps maintain high code quality, always applies itself against its own source code to demonstrate the quality and capabilities of itself. This process is called dogfooding. Dogfooding gives us confidence. At the same time, when we are careless and don’t pay attention to certain things, dogfooding alerts us immediately.

For every software products, it’s impossible to say they are bug-free or smell-free. But dogfooding is a very good practice to lower the change of being exploded to defects. Along with the growth of OCLint rule set, we always keep our code away from violating any of these rules.

Requirements

Always build the local OCLint version, and use it to dogfooding the codebase that this binary is built from. We also need to the latest development version of oclint-json-compilation-database helper program. Please refer Building OCLint for instructions. After building binaries and libraries for each module, please remind to call buildRelease.sh script that automatically gathers all parts from different modules, and assembles them properly in oclint-release directory.

Dogfooding

Kick off the dogfooding process by calling dogFooding.sh script in oclint-scripts folder, like

cd oclint-scripts
./dogFooding.sh

This will use CMake to configure the modules with CMAKE_EXPORT_COMPILE_COMMANDS on for generating compile_commands.json files. oclint-json-compilation-database follows after that to analyze the source code and generate dogfooding reports. It takes a while to finish the entire inspection process. When it’s done, the report will be outputted on terminal.

Note

Please help to keep your fork of OCLint codebase free from code smells. Before submit a patch or open a pull request, please make sure to run dogfooding and fix all violations. Great thanks.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Development »

Open Projects

This page contains a TODO list in a large picture. You can understand it as a road map. Some of them are small, but some are infinitely big. Implementation schedule of these projects are very flexible, we also release partial progress of some big projects if they look good and provide benefits to users.

OCLint started as a research project, so in addition to the features that are designed for industrial usage, there are some projects here that could be very interesting research projects in their own right. Users can leverage the research results for higher accuracy, better performance, more reasonable software metrics, and so on.

In any case, we welcome all contributions. If you are thinking one of them, please send an email to oclint-dev mailing list [https://groups.google.com/group/oclint-dev], so that we know this is being worked on. Please use the same mailing list to suggest more projects to this page.

More Rules

Rules are always welcome.

More Reporters

Reporters are also great welcome. We also plan to support major continuous integration systems, e.g. TeamCity and CruiseControl, by adding reporters and/or implementing plugins.

More Metrics

More interesting metrics can help developers measure their source code in different aspects. In addition to existing metrics, we are planning to add more metrics, like Weighted Method Count (WMC), Tight Class Cohesion (TCC), Access to Foreign Data (ATFD), Assignment-Branch-Condition (ABC), and so on.

OCLint’s metrics module is actually a cohesive library, it can be reused in your project without any OCLint dependencies. So, the new introduced metrics should only depend on abstract syntax tree representation.

Better Build System

Using bash scripts to organize the build system is not as good as letting the build system handles this by itself. We already use CMake in every modules, so now, we need to figure out a way to let CMake handle all projects under the OCLint umbrella.

Package Manager Build

We hope to provide native support for major package mangers, like homebrew for Mac and APT for Debian and its derived distributions.

Xcode Plugin/Addon/Extension

We are happy with existing oclint-xcodebuild, but we also want to provide a graphic interface for Xcode users. The idea is either being a Xcode plugin to be able to invoke OCLint inside Xcode, or being a standalone extension to open a Xcode workspace/project, select scheme, target, and other settings, then show source code with inline analysis results.

Control Flow Graphic Engine

A strong control flow graphic engine can help with a better understand of the order that statements, expressions, and functions are evaluated or executed. For instance, goto statements force program to jump to a different statement, if statements execute a branch of statements only if certain conditions are met, while statements run the code inside a loop iteratively, etc. It helps increase the analysis accuracy and avoid false positives.

We have applied control flow analysis in some existing rules, but we would like to have an engine to gain a more comprehensive understanding of the source code.

Data Flow Engine

Data flow provides global information about how a procedure manipulates its data, such as the use, declaration and dependency of the data. For example, a new value could be assigned to an existing variable, and the memory address of a pointer can be reallocated.

It is easier to detect the data flow in runtime. However, certain dynamic behaviors of the data can be also determined in static code analysis with data flow engine. Data flow engine is a big supplement to control flow engine.

Code Duplication and Logic Duplication Detection

We hope to apply Rabin–Karp string search algorithm [http://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_string_search_algorithm] in code duplication detection.

When it comes to logic duplication detection, there are many interesting experiments that we can conduct. But first of all, your humbled author has to admit that currently I don’t have a complete definition of logic duplication. But let’s think about the following interesting case:

Let’s say, 20 years ago, long before I join my current company, a senior developer had written a method like this

void foo(int x, int y)
{
     cout << x - y;
     cout << x * y;
}

And 10 years ago, he left the company. But his code is still in a base level library.

I joined this company after my graduation from college, 10 years after he left the company, so almost all my teammates even don’t know the existence of the method above. And one day, I occasionally write something like this

void bar()
{
    cout << 1 + 2;
    cout << 1 - 2;
    cout << 1 * 2;
    cout << 1 / 2;
}

Now, in this case, I really hope to be informed that I can change my code to

void bar()
{
    cout << 1 + 2;
    foo(1, 2);
    cout << 1 / 2;
}

This might not be a perfect example, but I hope you can feel a little bit about the meaning of logic duplication here. This is a valuable feature to many organizations that have to maintain large codebase, especially with many legacy code. In order to find out the logic duplication in the early stage of development can truly help them reduce the high maintenance in the future.

Refactoring Suggestions

In addition to detecting code defects that break our defined rule set, we hope to provide you suggestions of how to improve your code by refactoring. We hope to do it smartly and intelligently that the suggestions will be given after fully analyzing the context of the rot code.

Design Patterns Extraction

It’s helpful to know the design patterns we have applied in our codebase.

Type Inference

We know we can sometimes cheat to let compilers happy with certain things. This is a very dangerous practice.

But, on the other hand, sometimes, we also want to take the advantages of the dynamic of programming languages, like void pointer in C and C++, and id in Objective-C, even though they are static typed languages.

In fact, we believe type inference, the technique of automatically deduce, either partially or fully, the type even at compile time.

However, this largely increase the false positive in static code analysis.

Luckily, as the development of programming language techniques, type inference is introduced as a technique to automatically deduce, either partially or fully, the type of an expression at compile time. Many static typed languages have type inference capabilities builtin nowadays, so that as a developer, even though it’s a static typed language, but you could omit the type annotations without explicitly telling the compiler the type.

In this case, we can apply the same technique in static code analysis in order to lower false positive, and improve the accuracy at the same time.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Development »

Related Clang Knowledge Base

OCLint uses Clang APIs heavily. This includes Tooling, Abstract Syntax Tree, and Matchers libraries. A certain level of prerequisite knowledge will be great helpful when developers work on OCLint, especially for people who write own custom rules.

Here is a list of links that comprehensively explain how these Clang libraries work, hope these could ease the development.

LibTooling

http://clang.llvm.org/docs/LibTooling.html

http://clang.llvm.org/docs/IntroductionToTheClangAST.html

http://clang.llvm.org/docs/JSONCompilationDatabase.html

Clang AST

http://clang.llvm.org/docs/IntroductionToTheClangAST.html

http://clang.llvm.org/docs/RAVFrontendAction.html

LibASTMatchers

http://clang.llvm.org/docs/LibASTMatchers.html

http://clang.llvm.org/docs/LibASTMatchersTutorial.html

http://clang.llvm.org/docs/LibASTMatchersReference.html

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Development »

Coding Standards

Please help us with consistent coding standards for a number of reasons:

Reduce the maintenance cost

Improve the readability

Ship source code as a product, in fact, it’s an art

Although there is no restricted rules to be followed in all instances, it’s still highly recommended that when you implement new code or fix existing code, use the same style that is already being used in other places of the codebase.

Naming Convention

In general, use camel case [http://en.wikipedia.org/wiki/CamelCase].

Class names

Should be nouns and start with an upper case letter, like EmptyIfStatementRule.

Variable names

Should be nouns, and start with a lower case letter, like ifStmt. Names for class attributes (fields, members) are recommended with a underscore as prefix, like _carrier.

Function names

Should be verbs, start with a lower case letter, like applyLoopCompoundStmt.

Use Spaces Instead of Tabs

Treat Compiler Warnings Like Errors

Don’t Use else after return

Having else or else if after statements that interrupt control flow, like return, break, continue, etc, is confusing. It warms the readability, and sometimes, it’s hard to understand. We have a rule implemented about this, so dogfooding can help identify them.

Don’t Use Inverted Logic

To make code easier to understand, code like

if (!foo())
{
    doSomething();
}
else
{
    doSomethingElse();
}

Should be changed to

if (foo())
{
    doSomethingElse();
}
else
{
    doSomething();
}

No States in Rules

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

next |

previous |

OCLint 0.7 documentation »

Release Notes

0.7

oclint:

Update LLVM/Clang to 3.3

Use clang_rt.profile library for testing

Apply Hamcrest concept in all test cases

Update build system settings to support more unix-list platforms, including FreeBSD

Redesign the RuleBase interface and introduce RuleCarrier

Redesign the RuleConfiguration by using std::map

Improvement to RuleCarrier by following Law of Demeter

oclint-metrics:

Add references

Add unit tests for existing metrics

Take care of extern “C”

oclint-rules:

Introduce AST matcher rules

Add references

Improvement to StdUtil

Rule scaffolding

Reporter scaffolding

Reconsider priorities for certain rules

Suppress warnings for

unused method parameters

unused local variables

high cyclomatic complexity

high npath complexity

high ncss value

Improvement to Existing Rules

support __objc_bool in related rules

improvement to redundant conditional operator rule

improvement to parameter reassignment rule

improvement to unused local variable rule

improvement to dead code rule

improvement to double negative rule

Fix #10 - CollapsableIfStatementsRule false positives

Fix #16 - MissingBreakInSwitchStatementRule false positive

Fix #34 - False unused local variable warning with try/catch

New Rules

misplaced null/nill check

broken null/nil check

redundant nil check

short variable name

long variable name

too many fields

too many methods

too many parameters

avoid branching statement as last in loop

jumbled incrementer

objective-c number literals

objective-c boxed literals

objective-c container literals

objective-c object subscripting

oclint-reporters:

Extract reporters module from core module

Add PMDReporter

Add XMLReporter

Add JSONReporter

oclint-clang-tooling:

Extract ClangTooling related frontend code to this module from core module

oclint-xcodebuild:

Support more major compilers

Parse xcodebuild log for CURRENT_WORKING_FOLDER

Push source out of CURRENT_WORKING_FOLDER to the bottom of the list

Support custom xocdebuild log path

Add support to certain projects with white space in their project name or file path

oclint-scripts:

Automatically delete all builds when buildRelease

Extract testAll from ci

Extract buildAll from ci

0.6

oclint:

Update LLVM/Clang to 3.2, and switch from libClang to libTooling

Completely redesign the project

Use libTooling for AST generation

Add metrics system

Better rule system

Introduce results analysis

Better reporters system

New command line interface

HTML report has a better UI design

oclint-metrics:

Add NCSS metric

Add statement depth metric

oclint-rules:

Add BitwiseOperatorInConditionalRule

Add BrokenOddnessCheckRule

Add CollapsibleIfStatementsRule

Add ConstantConditionalOperatorRule

Add DoubleNegativeRule

Add ForLoopShouldBeWhileLoopRule

Add GotoStatementRule

Add MultipleUnaryOperatorRule

Add ReturnFromFinallyBlockRule

Add ThrowExceptionFromFinallyBlockRule

Add DefaultLabelNotLastInSwitchStatementRule

Add InvertedLogicRule

Add MissingBreakInSwitchStatementRule

Add NonCaseLabelInSwitchStatementRule

Add ParameterReassignmentRule

Add SwitchStatementsShouldHaveDefaultRule

Add TooFewBranchesInSwitchStatementRule

Add EmptyCatchStatementRule

Add EmptyDoWhileStatementRule

Add EmptyElseBlockRule

Add EmptyFinallyStatementRule

Add EmptyForStatementRule

Add EmptySwitchStatementRule

Add EmptyTryStatementRule

Add EmptyWhileStatementRule

Add RedundantConditionalOperatorRule

Add UnnecessaryElseStatementRule

Add UselessParenthesesRule

Add LongClassRule

Add LongLineRule

Add NcssMethodCountRule

Add NestedBlockDepthRule

oclint-json-compilation-database:

Initial release

oclint-xcodebuild:

Initial release

0.4.3

Added benchmark, use -stats to show

Smarter tree traversing policy, change traversing policy based on current node type

Extract Driver logic from main.cpp to separate class

Load clang header files by default, there is no need to put it into the header search path manually

Enable automatic reference counting (ARC) with -fobjc-arc flag

Automated PackageMaker for pkg installer generation

Code formatting

0.4.2

Add description to violations

0.4.1

Refactoring: aggressively extract methods

Update LLVM/Clang to 3.1svn

0.4

Command line options to configure input/output, compiler’s behaviors, rules’ thresholds and report formats

HTML report supported

Rule configurations supported

Fixed the false-positive for parameters in a block implementation

0.2.6

Check AST nodes which are declared within the current file being inspected

Separate unused method parameter rule from unused local variable rule

For unused local variable, ignore global variables that is not in a block

Use clang_visitChildrenWithBlock to make the code cleaner and easier to understand

Fix the false positive for unused method parameter in a pure C function

Fix the crash when there is no rule dylib in the folder specified

Use lcov to replace zcov as code coverage generation framework

0.2.4

Treat warnings as violations

Adopt new CursorExtractionUtil using awesome __block feature to replace old TestCursorUtil

New build configuration for libclang

New rules

Long parameter list

Long method

Unreachable code

Constant if statement

If statement with negated condition

Redundant if statement

Redundant local variable

NPath complexity

0.2

Initial academic research release

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

previous |

OCLint 0.7 documentation »

Modified BSD License

Copyright (C) 2010-2013 Longyi Qi. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

© Copyright Longyi Qi. Created using Sphinx 1.1.3.

Navigation

index

OCLint 0.7 documentation »

Index

© Copyright Longyi Qi. Created using Sphinx 1.1.3.