Yokasoft                  Home  Release Notes  Documentation  Screen Shots  Links
What is CodeInspect

CodeInspect is a code source inspector or a lint as commonly known. It analyses your C/C++ source code and reports non-portable, suspicious or plain wrong code. CodeInspect can be used to enforce good coding practices or corporate coding rules, to help automate the code review process, to check for code portability and to perform quality assurance testing directly on the source code.

CodeInspect can currently enforce 24 rules. Each rule can be enabled or disabled depending on the user's preferences.

How to Use CodeInspect

There are many different ways to use CodeInspect:

1- Using CodeInspect.exe

  1. From the Tools menu, select Inspect.
    The Inspect Project appears.
  2. Click on the [...] button and select the project you want to inspect.
  3. Select the desired configuration from the drop list.
  4. Click Inspect
    The result of the inspection will appear in the output pane.

2- Directly inside Visual C++.

You can use CodeInspect directly from the Visual C++ IDE. To integrate CodeInspect into MSVC do the following:

Choose Tools/Customize/Tools and add a new item to the list, then fill the field like this:

  • Tools name : CodeInspect
  • Command: (CodeInspect path)\DspLint.exe
  • Arguments: $(WkspName)
  • Initial directory: $(WkspDir)
  • Use Output Window: Yes
  • Prompt for arguments: Yes or No

CodeInspect can now be used from within MSVC by selecting the CodeInspect menu item from the Tools menu. The whole project will be inspected. The result will be send to the output window. You can double-click on a message and the IDE will jump to the line of code where the message occurred.

If you want to inspect your project using a different configuration than the default one, you can enable the option Prompt for arguments and specify the correct configuration on the Tool arguments dialog box.

3- Using your existing makefiles.

You can use CodeInspect with your existing makefiles. The only requirement is that inside the makefile the compiler (CL) is never called directly but always via a nmake macro. Like this:

CPP = cl.exe

Fortunately, the Visual C++ generated makefiles are doing exactly this.

To inspect an entire makefile, you just have to execute it with nmake while redefining the CPP macro on the command line:

nmake /f project.mak CPP=Lint

4- With the command line utility DspLint.

DspLint is a tool that inspect an entire Visual C++ project. To use DspLint you simply have to specify the name of your project on the command line.

DspLint MyProject.dsp

This will inspect all sources in project MyProject.dsp using the default configuration. Optionally, you can force DspLint to use a particular configuration by putting the name of the configuration after the name of the project file.

DspLint MyProject.dsp "MyProject - Win32 Debug"

 

5- With the command line utility Lint.

If you don't have a lot of files to inspect, you can execute Lint directly. For example, if you want to inspect a file called test.cpp:

Lint test.cpp

Or if you have two files:

Lint test1.cpp test2.cpp

Lint support the same options accepted by Microsoft's CL compiler. You can therefore specify command line options as if Lint was CL.

Lint -D DEBUG test.cpp

How to Configure CodeInspect

  1. Start CodeInspect.exe
  2. From the Tools menu, select Setting.
    The setting dialog box appears.

Here is a description for each option that can be customized.

Ignore duplicate messages

If you enable this option, Lint will never show the same error twice even if the error occur in a header file that is included in many source files.

Use INCLUDE environment variable

If you enable this option, Lint will search for include files along the paths specified by the INCLUDE environment variable.

Ignore warnings in system headers

If you enable this option, Lint will ignore all warnings that occur in system headers. Since you should never edit the system header files, you probably want to enable this option.

Use Visual C++ directories setting.

If you enable this option, Lint will search for include files along the paths specified in the 'Option/Directories/Include files' setting of Visual C++.

System include directories

Allow you to specify additional paths where Lint will try to find system include files. Put each directory on a separate line.

Ignore directories

Lint will not report warnings that occur in files located in the directories and all subdirectories specified there. Put each directory on a separate line.

Messages list

Allow you to enable or disable each warning depending on your needs.

DspLint command-line syntax

DspLint allows you to inspect an entire project created by Visual C++. DspLint works by extracting all the necessary information from the project (.dsp) file and calling Lint for each source file with the appropriate options.

DspLint [/c] <myprj.dsp | mywksp.dsw> [<configname>]

If you specify a workplace (.dsw) file, DspLint will look for a project (.dsp) file with the same name in the same directory. If the file doesn't exist, an error will occur.

Optionally, you can specify to DspLint what configuation to use to parse the project's files with configname. For example, Lint will not parse the code within an #ifdef _DEBUG directive if the configuration is of release type and thus the macro _DEBUG undefined. If no configname is specified, DspLint will use the default configuration as defined in the project (.dsp) file. Configname must be enclosed within double quote (").

/c : This option displays the available configurations for the project without inspecting the source code.

Usage example

dsplint project.dsp

dsplint project.dsw

dsplint /c project.dsw

dsplint project.dsp "Project - Win32 Debug"

dsplint project.dsp "Project - Win32 Release"

Lint command-line syntax

The Lint command line utility uses the following syntax:

Lint [option...] file... [option | file]... [lib...] [@command-file] [/link link-opt...]

This syntax is exactly the same as the one supported by Microsoft's CL compiler. Lint will ignore the options that are not needed for its execution and take meaningful actions for some options that affect the way Lint parses a file. For example, Lint will recognize the /D (Macro Definition) option and add the macro to your source file.

It is important to note that Lint is designed to act as a substitute for CL. You don't have to learn a different set of options for Lint and for CL. This make it possible to just substitute Lint for CL in your makefile and execute it with nmake. Lint will then parse your source code just fine.

Fatal Error F1001

Unknown message

The message is unknown to the parser.

Fatal Error F1002

Out of memory ('file', 'line number')

Lint ran out of memory during execution. You may need to quit all others applications before executing lint. If that doesn't work, you may need a computer with more memory in order to parse the file.

'file' and 'line number' represent the location in the lint source code where lint failed to allocate more memory.

Fatal Error F1003

Process memory is corrupted ('file', 'line number')

Lint cannot continue execution due to memory corruption. This is most likely due to a defect in the lint program. Please fill a bug report.

'file' and 'line number' represent the location in the lint source code where lint detected the memory corruption.

Fatal Error F1004

Internal parser error('file', 'line number')

Lint has entered in an invalid state and cannot continue execution. This is most likely due to a defect in the lint program. Please fill a bug report.

'file' and 'line number' represent the location in the lint source code where lint entered in an invalid state.

Fatal Error F1005

Window SEH error

Lint cannot continue execution due to an unexpected Windows Structured Error Exception. This is most likely due to a defect in the lint program. Please fill a bug report.

Parser Error P2001

Illegal character 'hex-character'

An illegal ASCII character appeared in the source code. The parser will ignore it.

Parser Error P2002

Unexpected end of file

End of file was detected in the middle of a C/C++ construct.

An example of this error is when you forget to close a C-style comment.

Parser Error P2003

Unexpected end of line

A new-line character is illegal at this point in the source code.

example

#define FUNC(A, // unexpected end of line.

B) A + B

Parser Error P2004

File 'filename' not found

'filename' could not be found while looking in the include directories list.

Make sure the system include directories are correctly set by using the program CodeInspect.

Parser Error P2005

Cannot open file 'filename'

'filename' was found but could not be opened.

Possible causes:

  • The file is already used by another application.
  • You do not have the permission to open the file.
  • Lint has run out of file handles.

Parser Error P2006

Invalid #include directive

The line does not form a valid #include directive.

example

#include bad // Invalid #include directive

Parser Error P2007

Invalid preprocessing expression constant

The expression inside #if is invalid.

example

// invalid: preprocessing expression

// cannot contains string literal.

#if TEST == "DEBUG"

//........

#endif

Parser Error P2008

Unexpected #elif directive

The #elif directive did not appear within an #if, #ifdef, or #ifndef construct.

Parser Error P2009

Unexpected #else directive

The #else directive did not appear within an #if, #ifdef, or #ifndef construct.

Parser Error P2010

Unexpected #endif directive

An #endif directive is not matched by a beginning #if, #ifdef, or #ifndef directive.

Parser Error P2011

Invalid preprocessor directive

The line does not form a valid preprocessing directive.

example

#invalid // Invalid #include directive

Parser Error P2012

Identifier expected

Lint was expecting a valid identifier at this point but found something else.

example

#define 1234 // Identifier expected

Parser Error P2013

Macro parameter 'identifier' redeclared

Macro parameter 'identifier' is used more than once in the parameter list of a macro definition.

example

#define ADD(a,a) a+a // Macro parameter 'a' redeclared

Parser Error P2014

')' expected

Lint was expecting a closing parenthesis at this point but found something else.

example

#define ADD (a,b // ')' expected

Parser Error P2015

#error directive: 'message'

An #error directive was detected while preprocessing file.

Parser Error P2016

#endif expected before end of file

An #if, #ifdef, or #ifndef construct was not closed by an #endif.

Parser Error P2017

#import directive is not supported

This version of CodeInspect doesn't support the #import preprocessing directive. Future version will.

Warning W3001

C++ style comment in C source

A C++ style comment was found in a C source file. While a lot of C compilers accept this as an extension, C code source that contain C++ comments are nonstandard and will cause portability problems with some compilers.

Warning W3002; W3003

Unused macro constant

Unused function constant

A macro was defined but is never used. Theses two warnings are more meaningful when detected at the end of a project. Then an unused macro may alert the programmer that he forgot to handle a particular situation or else that the macro is no longer needed. If no longer needed, it may be better to delete the unused macro to avoid confusion and to facilitate maintenance.

Warning W3004

System header should be included using < and > delimiters : <header>

It's a good idea to always include system headers using the <> delimiters and project specific headers using the "" delimiters. Doing so helps to distingue between the two kinds of header and make the code more explicit and easier to understand.

example

#include "stdio.h" // warning W3004

prefer:

#include <stdio.h>

Warning W3005

Nonstandard charizing operator '#@' used

The charizing operator is a Microsoft specific compiler extension. Do not use it if you want your source code to be portable.

example

// Nonstandard charizing operator '#@' used

#define PRINT_CHAR(c) putchar(#@c)

Warning W3006

Use of old style C++ ANSI/ISO header 'old-header', prefer 'new-header'

A C++ standard header was included in the old way with a .h extension. With the adoption of the C++ standard, header names now contain no extension. For backward compatibility, Visual C++ still provides some headers with the old notation that contain old C++ library code. Those headers should be avoided in favor of the template based new headers.

List of old header names with their corresponding new header names

Old header name New header name
fstream.h fstream
iomanip.h iomanip
ios.h ios
iostream.h iostream
istream.h istream
list.h list
memory.h memory
new.h new
ostream.h ostream
queue.h queue
stdexcpt.h stdexcept
typeinfo.h typeinfo

Warning W3007

Use of old style ANSI C header 'old-header' in C++ source, prefer 'new-header'

A C header was included in a C++ file using the form <header.h>. While this practice is allowed by the C++ standard, a better alternative is to use the form <cheader>. This latter form has the advantage of placing all the declarations and definitions within the scope of the namespace std.

List of old header names with their corresponding new header names

Old header name New header name
assert.h cassert
ctype.h cctype
errno.h cerrno
float.h cfloat
iso646.h ciso646
limits.h climits
locale.h clocale
math.h cmath
setjmp.h csetjmp
signal.h csignal
stdarg.h cstdarg
stddef.h cstddef
string.h cstring
stdio.h cstdio
stdlib.h cstdlib
time.h ctime
wchar.h cwchar
wctype.h cwctype

Warning W3008

'header' is not an ANSI C header

'header' is not part of the header list that every C implementation must provide. There is no guaranty that 'header' will be available on another implementation or platform. Enable this warning only if you want your source code to depend only on ANSI C header. This warning is reported only for headers found in the system include paths.

example

#include <conio.h> // 'conio.h' is not an ANSI C header

Warning W3009

'header' is not an ANSI/ISO C++ header

'header' is not part of the header list that every C++ implementation must provide. There is no guaranty that 'header' will be available on another implementation. Enable this warning if you want your source code to depend only on ANSI/ISO C++ header. This warning is reported only for headers found in the system include paths.

example

#include <conio.h> // 'conio.h' is not an ANSI/ISO C++ header\

Warning W3010; W3011

Macro constant identifier should be all uppercase

Macro function identifier should be all uppercase

It is common practice to make the name of macro identifiers all uppercase. Macro can have some undesirable behaviors and giving them all uppercase names makes it easier to spot them in the source. The source is then easier to understand and maintain.

example

// Macro constant identifier should be all uppercase

#define this_is_a_constant_macro 1

#define this_is_a_function_macro(a) a+1

Warning W3012

Parentheses are missing around a complex macro

A macro that contains complex expression without being parenthesized is prone to error when expanded inside another expression. Because operator precedence rules apply only after all expansions are done, the result may not be what the programmer would expect (see example). It is then better to always surround all expression macro within parentheses.

Note that CodeInspect will report this warning only for macro that looks like expression.

example

#define ADD(arg1, arg2) arg1 + arg2

...

int a = ADD(1,2) * 3;

This line will expand to

int a = 1 + 2 * 3;

Which by operator precedence means:

int a = 1 + (2 * 3);

Variable a will be assigned value 7, not 9 as common sense would imagine by reading the initial nonexpanded expression. This is surely not what the programmer was expecting.

A better alternative is to replace the macro ADD by an inline function.

Warning W3013

Parentheses are missing around a macro parameter 'param'

Parentheses are missing around a macro parameter. Macro parameters in the replacement text of a macro definition should always be surrounded by parentheses. Otherwise subtle operator precedence errors could occur if the actual macro argument is a complex expression. This kind of error is similar to the one described in Warning W3012.

Note that CodeInspect will report this warning only for macro that looks like expression.

example

#define MUL(a,b) a * b

int a = MUL(2 + 3, 2)

This line will expand to

int a = 2 + 3 * 2;

Which by operator precedence means:

int a = 2 + (3 * 2);

Variable a will be assigned value 12, not 10 as common sense would imagine by reading the initial nonexpanded expression. This is surely not what the programmer was expecting.

A better alternative is to replace the macro MUL by an inline function.

Warning W3014

A macro argument 'name' with side effects is evaluated more than once after macro expansion

The macro argument 'name' contains side effects and will be evaluated many times because of macro expansion. This will cause some variables to be modified several times without being apparent in the source code. This is most probably a programming error. Don't put expressions with side effects as macro argument.

example

#define MAX(n1, n2) ( ( (n1) > (n2) ) ? (n1) : (n2) )

int a = 2;

int b = 3;

int max = MAX(++a, ++b);

After macro expansion the last line will become

int max = ( ( (++a) > (++b) ) ? (++a) : (++b) );

After execution a will take value 3, b value 5 and max value 5. b++ will be evaluated twice because b is larger and thus only the second expression after the ? will be evaluated. This kind of code is confusing and hard to maintain and should be avoided. To fix the problem, put the increments on separate line:

a++;

b++;

int max = MAX(a, b);

A better alternative is to replace the macro MAX by an inline function.

Warning W3015

Identifier 'name' is reserved for the implementation use

'name' is reserved by the implementation and should not be used as an identifier in your source code. The C++ standard states that some names are reserved and should never be used.

Currently Lint will emit this warning for :

  • A macro name that contains a double underscore ( __ )
  • A macro name that begins with an underscore ( _ )

example

// Identifier '_ONE' is reserved for the implementation use

#define _ONE 1

Warning W3016

Assignment '=' inside an if

A common mistake in C/C++ program is to use '=' instead of '==' inside an if assignment expression. This will result in the left variable to be assigned instead of being compared.

if (a = b) // Assignment '=' inside an if

The warning will not occur if the assignment (=) is not the controlling expression.

if ( (a = b) != 0 ) // Ok

It is possible to imagine cases where it makes sense to use '=' inside an if, for example:

if (ptr = malloc(1024))

{

// Handle correct allocation.

}

While this code is valid and correct, it would be better to separate the memory allocation and the test for failed allocation. You then avoid having to use '=' inside an if. This makes the code easier to understand and maintain.

ptr = malloc(1024)

if (ptr)

{

// Handle correct allocation

}

or alternately you can embed the assignment inside parentheses and make the comparison to 0 explicit:

if ( ( ptr = malloc(1024) ) != 0 ) // No warning

Warning W3017

Assignment '=' inside a while

An assignment '=' is the controlling expression inside a while. This is suspicious! Is this the intent ? Maybe you wanted to write the equality operator '=='. This warning is similar is W3016.

example

while (a = 0) // Assignment '=' inside a while.

Warning W3018

Enum forward declaration is a nonstandard

Enum forward declaration is not part of the C++ standard. Do not use this feature if you plan to port your source code on another compiler or platform.

example

enum Color; // Enum forward declaration is nonstandard

Color* color;

Warning W3019

Macro 'macro-name' could be a const variable

It is usually preferable to use a const variable instead of a macro. A variable has a scope and a type whereas a macro doesn't obey to scope rules and has no type.

For example, if your program contains another identifier that has the same name as the macro but inside another scope, your program will not compile or work correctly because the macro will overwrite the identifier.

example

#define RED 5

class Color {
enum { RED, BLUE, GREEN } color;
// this line will not compile
};

const int RED 5

class Color {
enum { RED, BLUE, GREEN } color;
// fine, global RED respect scope
};

Warning W3020

Macro 'macro-name' could be an inline function

It is usually preferable to use an inline function instead of macro function. Using inline functions has many advantages over macros:

  • Inline functions have scope, macros don't.
  • Inline functions can be overloaded, macros cannot.
  • Inline function don't have the problems associated with the textual substitution nature of macros as explained in W3012, W3013, W3014.

Warning W3021

'header' has already been included

Indicate that 'header' has already been included in the same file. The include directive is thus unnecessary and should be removed.

example

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
// 'windows.h' has already been included

Warning W3022

'using namespace std' is not recommended

By declaring 'using namespace std' in your program, you are effectively defeating the purpose of namespace. 'using namespace std' will makes all the names from the standard library available as if they had been declared outside the std namespace. It is better to use using-declaration (ex: using std::string) or explicitly prefixing std:: in front of standard library names. This way make it clear if a name comes from the standard library or not

example

#include <vector>
#include <string>
using namespace std;

class Data {
string str;
vector<int> vec;
}

It is better to write the preceding program like this:

#include <vector>
#include <string>
using std::vector;
using std::string;

class Data {
string str;
vector<int> vec;
}

or like this

#include <vector>
#include <string>
class Data {
std::string str;
std::vector<int> vec;
}

Warning W3023

Assignment to self

An variable that is assigned to itself was detected in the source code. This is most probably due to a typing error.

example

class Data{
public:
void SetData(int in_Data) { m_Data = m_Data; }
// Oops... Assignment to self

private:
int m_Data;
}

Warning W3024

Using == or != with floating point values in dangerous

Be very cautious when using == or != with floating point values. Because of the way they are designed, floating point values are only approximate. Floating point operations always introduce small round-off errors and there is no perfect representation of fractions. Use == and != with floating values only if you perfectly understand the consequences of doing so.

example

This code will cause an infinite loop on Visual C++ 6:

for (double i=0; i != 1; i+=0.1){
cout << i << "\n";
}

Instead use the relational operator: <, <=, >, >=

for (double i=0; i < 1; i+=0.1){
cout << i << "\n";
}

Copyright © 2006 Yokasoft.  All rights reserved