Because you want:
To understand which methods/classes should be reworked
Your development team to identify potential risks
To track progress during software development
Basically, when you
Have a large codebase
Work in heterogeneous teams
Are writing an auditWant to get a rapid overview of an inherited codebase
Cyclomatic complexityfunc example(a: Int, b: Int, c:Int, d:Int) { // 1 if a == b { // 2 println("Hello") } else if (c == d) { // 3 for index in 1...5 { // 4 println("Hello") } } else { // 5 switch c { case 1: // 6 println("Hello") case 2: // 7 println("Hello") default: // 8 println("Hello") } }}
NPath complexityfunc example(a:Int, b:Int) { if a > 10 { println(1) } else { println(2) } if a > b { println(3) } else { println(4) }}// Result: 4
PMD
Java static analyzer - a must-have of the Java developer
Supports Java, JavaScript, XML
Identifies:• Unused variables
• Empty catch blocks
• Unnecessary object creation
• Cyclomatic/NPath complexity
Clang Static Analyzer
Part of the Clang project
Run as standalone or included via Xcode
Analyzes the different execution paths (Abstract Syntax Tree)
Detects wether some paths can lead to problems
AppCode
Performs checks for:
• Clang analysis
• Class errors (hidden scopes, missing implementations)
• Data flow analysis
• Obsolete vs Modern syntax checking
• String localisation control
• Unavailable/deprecated APIs
gcovr
Generates code coverage reports from .gcda and .gcno files
Exports to the Cobertura1 XML format
.gcda and .gcno files are generated by setting
• GCC_GENERATE_TEST_COVERAGE_FILES
• GCC_INSTRUMENT_PROGRAM_FLOW_ARCS
1 - Cobertura: an open source tool for measuring Java code coverage
OCLint
Inspired by PMD and by the AppCode static analyzer
Based on Clang
Exports to the PMD file format
OCLint
Detects:• Empty control flow statements
• Unused code
• Complicated code (high cyclomatic/NPath complexity, deep statements)
• Redundant if statements
• Long methods, long parameter list
OCLint - Installing
http://docs.oclint.org/en/dev/intro/installation.html
Make the binary available from your path
SonarQube
A Web Application for Continuous Inspection of code quality
Acts as an hub for code metrics
Integrates with other tools such as PMD, Cobertura or OCLint
SonarQube Runner
Is the frontend for executing sonar
Reads a sonar-project.properties file in the project folder
SonarQube Objective-C plugin
Developed by Octo Technologies, Parisgithub.com/octo-technology/sonar-objective-c
Aggregates:• OCLint results
• Test coverage (via Cobertura)
• CPD
A real life project
1. Jenkins
2. xcodebuild/xctool/xcpretty
3. OCLint
4. Run Tests
5. Run gcovr
6. Sonar
1. Jenkins
Runs project jobs
A job can consist in compilation, testing, analysis, deployment tasks
Jobs can be parametrized
3. OCLint
$ oclint-xcodebuild # Generates compile_commands.json
$ oclint-json-compilation-database > -- -report-type pmd -o sonar-reports/oclint.xml
4. Run tests
$ GCC_GENERATE_TEST_COVERAGE_FILES=YES > GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES > /usr/bin/xcodebuild test | xcpretty -tc --report junit > --output "${PWD}/sonar-reports/TEST-report.xml"
5. Run gcovr
$ ./scripts/gcovr -r . PATH/TO/DUCKING/DERIVEDDATA/ > --exclude .*Tests.* --xml > > "${PWD}/sonar-reports/coverage.xml"
6. Sonar-Runner - Property file
sonar.projectKey=nsspaindemosonar.projectName=NSSpainDemosonar.language=objcsonar.projectDescription=NSSpainDemosonar.sources=NSSpainDemo/sonar.objectivec.project=NSSpainDemo.xcodeproj
Putting it all together
#!/bin/bash
BUILD_CMD_SUFFIX="-project ${PROJECT_NAME}.xcodeproj -derivedDataPath ${PWD}/DerivedData -configuration Debug" \
# Clean the foldersrm -rf ${PWD}/sonar-reportsrm -rf ${PWD}/DerivedDatamkdir ${PWD}/sonar-reports
# Build/usr/bin/xcodebuild ${BUILD_CMD_SUFFIX} -scheme "${DEFAULT_SCHEME}" \ -sdk "${DEFAULT_SDK}" > xcodebuild.log
# Generate compile commands/usr/local/bin/oclint-xcodebuild/usr/local/bin/oclint-json-compilation-database "${PWD}/${PROJECT_NAME}" \ -- -report-type pmd -o sonar-reports/oclint.xml
# Run testsGCC_GENERATE_TEST_COVERAGE_FILES=YES \ GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES \ /usr/bin/xcodebuild ${BUILD_CMD_SUFFIX} -scheme "${DEFAULT_SCHEME}" \ -sdk "${DEFAULT_SDK}" test | xcpretty -tc --report junit \ --output "${PWD}/sonar-reports/TEST-report.xml"
# Generate coverage report./scripts/gcovr -r . \ ${PWD}/DerivedData/Build/Intermediates/"${DEFAULT_SCHEME}".build/Debug-iphonesimulator/"${DEFAULT_TARGET}".build/Objects-normal/i386 \ --exclude .*Tests.* --xml > "${PWD}/sonar-reports/coverage.xml"
# Send results to SonarQube/usr/local/bin/sonar-runner
exit $?
Final thoughts
• Automate, automate, automate
• Code metrics are not Gospel
• Static analysis alone is not enough
• Pick a range of complementary metrics
• Be honest with yourself
• Aim for all metrics rather than excelling in a single one