// CodeCheck (c) 2005 Rule-File for C++ Coding Standard Abraxas Software [ CCS.CC ]
// CodeCheck Rule-File to automate "C++ Coding Standards" text by Alexandrescu & Sutter
// CodeCheck (c) 2005 Rule-File for C++ Coding Standard Abraxas Software [ CCS.CC ]
// CodeCheck Rule-File to automate "C++ Coding Standards" text by Alexandrescu & Sutter
#include "ccs.cch"
/*
This rule file has two purposes. The first is to help find problems documented
in the CCS book. The second purpose is show people how to write CodeCheck rule-files.
If you study the below CC source you'll see many DEBD() [ccdebug.cch] statements that have
been commented out, if you remove the comments then you can generate diagnostics to learn
what codecheck is actually doing.
This large rule-file ccs.cc is really just an example of a rule-file system. In actuality
many of these rule's should be ran as individuals because many of the rule's in fact many
diagnostics and the entire system ran as ccs.cc generates too much data on real production
code.
*/
// BEGIN OF RULE-FILE CCS
/*
A. Organizational and Policy Issues.
0) Don't sweat the small stuff. (Or: Know what not to standardize.).
1) Compile cleanly at high warning levels.
2) Use an automated build system.
3) Use a version control system.
4) Invest in code reviews.
B. Design Style.
5) Give one entity one cohesive responsibility.
6) Correctness, simplicity, and clarity come first.
7) Know when and how to code for scalability.
8) Don't optimize prematurely.
9) Don't pessimize prematurely.
10) Minimize global and shared data.
11) Hide information.
12) Know when and how to code for concurrency.
13) Ensure resources are owned by objects. Use explicit RAII and smart pointers.
*/
// C. Coding Style.
// 14) Prefer compile- and link-time errors to run-time errors.
// 15) Use const proactively.
if ( dcl_parameter ) {
//DEBDL("DP")
if ( dcl_level_flags(0) & CONST_FLAG ) {
CCS_C( 15, "Use const proactively." );
}
}
// 16) Avoid macros.
// warn on use of macros
if ( lex_macro_token ) {
CCS_C( 16, "Avoid macro - Usage." );
}
// warn on definition of macros
if ( lin_preprocessor ) {
//warn(16, "LP %d", lin_preprocessor );
if ( lin_preprocessor == DEFINE_PP_LIN ) {
CCS_C( 16, "Avoid macro - Definition." );
}
}
// 17) Avoid magic numbers.
if ( lex_constant ) {
//warn( 17, "LC %d k%d", lex_constant, tag_kind );
// verifty raw # and not within a tag { enum, class, ... }
if ( lex_macro_token == 0 && tag_kind == 0 && isdigit(token()[0]) ) {
CCS_C( 17, "Avoid magic numbers." );
}
}
// 18) Declare variables as locally as possible.
/*
The theory here is two problems, NOT only the decl, but the usage, the usage of the global
is important, .e.g. if you mission is to fix code. Before you mod the decl, you need to know
what your effecting.
*/
if ( dcl_variable ) {
if ( dcl_global && lin_within_namespace == 0 ) {
CCS_C( 18, "Declare variables as locally as possible. [ declaration ]" );
}
}
if ( idn_variable ) {
if ( idn_global ) {
CCS_C( 18, "Declare variables as locally as possible. [ usage ]" );
}
}
// 19) Always initialize variables.
// trigger on the case of a non-init being used.
if ( idn_no_init ) {
CCS_C( 19, "Always initialize variables - usage." );
}
// trigger on the case of a declare without an init
if ( dcl_variable ) {
//warn( 19, "DL %s di%d", dcl_name(), dcl_initializer ) ;
if ( dcl_initializer == 0 && dcl_simple ) {
CCS_C( 19, "Always initialize variables - declare." );
}
}
// 20) Avoid long functions. Avoid deep nesting.
int deep_nest;
if ( fcn_begin ) {
deep_nest = 0;
}
if ( op_open_brace ) {
++deep_nest;
if ( deep_nest > NEST_DEPTH ) {
CCS_C( 20, "Avoid long functions. Avoid deep nesting. [ DEEP_NEST ]" );
}
}
if ( op_close_brace ) {
--deep_nest;
}
if ( fcn_end ) {
if ( fcn_total_lines > LONGFUNC ) {
CCS_C( 20, "Avoid long functions. Avoid deep nesting. [ LONGFUNC ]" );
}
if ( fcn_decisions > MILLER_NUM ) {
CCS_C( 20, "Avoid long functions. Avoid deep nesting. [ MILLER_NUM ]" );
}
}
/*
21) Avoid initialization dependencies across compilation units.
*/
if ( dcl_variable ) {
if ( lin_within_namespace ) {
CCS_C( 21, "Avoid initialization dependencies across compilation units." );
}
}
// 22) Minimize definitional dependencies. Avoid cyclic dependencies.
int type;
if ( dcl_member ) {
if ( lin_within_class && lin_source ) {
// set idn_filename() to class-name, rather than member-name
type = find_root( dcl_base_name() );
//warn( 22, "B:%s t%d C:%s t%d", dcl_base_name(), dcl_base, class_name(), type );
if ( type && dcl_simple == 0 )
{
if ( strncmp(file_name(),idn_filename(),BIGIDLEN) )
{
CCS_C( 22, "Minimize definitional dependencies. Avoid cyclic dependencies." );
}
}
}
}
// 23) Make header files self-sufficient.
if ( lin_preprocessor ) {
if ( lin_header && lin_header == PRJ_HEADER ) {
//warn( 23, "LP-LH %d", lin_preprocessor );
if ( lin_preprocessor == INCLUDE_PP_LIN ) {
CCS_C( 23, "Make header files self-sufficient." );
}
}
}
// 24) Always write internal #include guards. Never write external #include guards.
int guard_seen;
char wrapper_name[MAXIDLEN+1];
if ( lin_preprocessor ) {
//warn(24, "LP %d %s gs=%d", lin_preprocessor, pp_name(), guard_seen );
switch ( lin_preprocessor ) {
case INCLUDE_PP_LIN:
if ( guard_seen )
guard_seen = 0;
else
guard_seen = -1;
break ;
case IFNDEF_PP_LIN: // #ifndef
if ( guard_seen < 0 ) {
guard_seen = lin_number;
strncpy( wrapper_name, pp_name(), MAXIDLEN );
}
break;
case DEFINE_PP_LIN: // #define
if ( strncmp(pp_name(),wrapper_name,MAXIDLEN)==0
&& (guard_seen+1) == lin_number ) {
//warn( 24, "CORRECT");
}
else {
CCS_C( 24, "Always write internal #include guards." );
}
guard_seen = 0;
break;
default:
// catch all case, empty headers ... external
if ( guard_seen ) {
CCS_C( 24, "Always write internal #include guards." );
}
guard_seen = 0; // done
break;
}
}
// D. Functions and Operators.
//25) Take parameters appropriately by value, (smart) pointer, or reference.
if ( dcl_parameter ) {
if ( dcl_base == CLASS_TYPE ) {
if ( dcl_level(0) != REFERENCE ) {
CCS_D( 25, "Take parameters appropriately by value, (smart) pointer, or reference." );
}
}
}
/*
26) Preserve natural semantics for overloaded operators.
*/
if ( op_open_funargs ) {
if ( lin_within_class && strncmp(op_function(),"operator",8)==0 ) {
if ( strchr(op_function(),'+') || strchr(op_function(),'*') )
{
CCS_D( 26, "Preserve natural semantics for overloaded operators.");
}
}
}
/*
27) Prefer the canonical forms of arithmetic and assignment operators.
*/
if ( op_open_funargs ) {
if ( (strncmp(op_function(),"operator",8)==0) && (strlen(token())==1) ) {
strcpy( TEMPBUF, op_function() ); // find operator@
strcat( TEMPBUF, "=" ); // append operator@=
// If an operator@ is seen then verify that the operator@= case is in class
if ( lin_within_class==0 && find_scoped_root( dcl_base_name(),TEMPBUF ) == 0 )
{
CCS_D( 27, "Prefer the canonical forms of arithmetic and assignment operators." );
}
}
}
/*
28) Prefer the canonical form of ++ and --. Prefer calling the prefix forms.
*/
/*
29) Consider overloading to avoid implicit type conversions.
*/
// 30) Avoid overloading &&, ||, or , (comma).
if ( dcl_function ) {
//warn(30, "DF %s %d", fcn_name(), dcl_base );
if ( lin_within_class && strncmp(dcl_name(),"operator",8)==0 ) {
if ( strstr(dcl_name(),"&&") || strstr(dcl_name(),"||") || strstr(dcl_name(),",") )
{
CCS_D( 30, "Avoid overloading &&, ||, or , (comma).");
}
}
}
// 31) Don't write code that depends on the order of evaluation of function arguments.
char pidn_name[MAXIDLEN+1];
if ( op_open_funargs ) {
pidn_name[0] = 0;
}
if ( op_pre_incr ) {
if ( incall )
{
if ( strncmp(idn_name(),pidn_name,MAXIDLEN)==0 ) {
CCS_D( 31, "Don't write code that depends on the order of evaluation of function arguments." );
}
strncpy( pidn_name, idn_name(), MAXIDLEN );
}
}
if ( op_return ) {
if ( strstr(next_token(),"++") ) {
CCS_D( 31, "Don't write code that depends on the order of evaluation of function arguments." );
}
}
// E. Class Design and Inheritance.
/*
32) Be clear what kind of class you're writing.
*/
// 33) Prefer minimal classes to monolithic classes.
if ( tag_end && tag_kind==CLASS_TAG ) {
i = 5;
while ( i>=0 ) {
//warn( 33, "TE %d c%d", i, tag_components(i,0) );
if ( tag_components(i,0) > MILLER_NUM ) {
CCS_E( 33, "Prefer minimal classes to monolithic classes." );
i = 0; // issue first message seen only
}
i--;
};
}
/*
34) Prefer composition to inheritance.
*/
if ( dcl_access_adjust ) {
//warn(342, "DAA %s::%s da=%d tba=%d", dcl_scope_name(), dcl_name(), dcl_access, tag_base_access );
CCS_E( 34, "Prefer composition to inheritance." );
}
/*
35) Avoid inheriting from classes that were not designed to be base classes.
*/
// 36) Prefer providing abstract interfaces.
int pureseen;
if ( tag_begin ) {
if ( tag_kind == CLASS_TAG ) {
pureseen = 0;
}
}
if ( tag_end ) {
if ( tag_kind == CLASS_TAG ) {
//warn(36,"TE p=%d tb=%d", pureseen, tag_bases );
if ( tag_bases == 0 && pureseen == 0 ) {
CCS_E( 36, "Prefer providing abstract interfaces." );
}
pureseen = 0;
}
}
if ( dcl_pure ) {
pureseen = lin_number;
}
/*
37) Public inheritance is substitutability. Inherit, not to reuse, but to be reused.
*/
// 38) Practice safe overriding.
int initzero;
if ( tag_begin ) {
initzero = lin_number;
}
if ( dcl_parameter ) {
if ( isdigit(prev_token()[0]) ) {
if ( atoi( prev_token() ) == 0 ) {
initzero = lin_number ;
}
}
}
if ( dcl_virtual ) {
//warn( 38, "DV %s iz=%d", dcl_name(), initzero );
if ( initzero != lin_number ) {
CCS_E( 38, "Practice safe overriding." );
}
}
/*
39) Consider making virtual functions nonpublic, and public functions nonvirtual.
*/
if ( dcl_function ) {
//warn(39, "%s %s dff=%d da=%d", class_name(), dcl_name(), dcl_function_flags, dcl_access );
if ( dcl_member ) {
if ( dcl_access == PUBLIC_ACCESS && dcl_function_flags & VIRTUAL_FCN ) {
CCS_E( 39, "Consider making virtual functions nonpublic" );
}
else if ( dcl_access != PUBLIC_ACCESS && (dcl_function_flags & VIRTUAL_FCN)==0 ) {
CCS_E( 39, "Consider making non-virtual functions public" );
}
}
}
/*
40) Avoid providing implicit conversions.
*/
if ( dcl_function ) {
// warn(40, "DF %s f%d", dcl_name(), dcl_function_flags );
if ( dcl_function_flags & OPERATOR_FCN ) {
if ( dcl_base >= VOID_TYPE && dcl_base < ENUM_TYPE ) { // primitive type's
CCS_E( 40, "Avoid providing implicit conversions." );
}
}
}
/*
41) Make data members private, except in behaviorless aggregates (C-stylestructs).
*/
if ( dcl_member ) {
//warn( 41, "DM %s dm%d a%d b%d", dcl_name(), dcl_member, dcl_access, dcl_base );
if ( dcl_access == PUBLIC_ACCESS
&& ( dcl_base == CLASS_TYPE || dcl_base < ENUM_TYPE ) ) {
CCS_E( 41, "Make data members private, except in behaviorless aggregates" );
}
}
// 42) Don't give away your internals.
// 43) Pimpl judiciously.
// 44) Prefer writing nonmember nonfriend functions.
// 45) Always provide new and delete together.
// 46) If you provide any class-specific new, provide all of the standard forms (plain, in-place, and nothrow).
// F. Construction, Destruction, and Copying.
/*
47) Define and initialize member variables in the same order.
48) Prefer initialization to assignment in constructors.
49) Avoid calling virtual functions in constructors and destructors.
50) Make base class destructors public and virtual, or protected and nonvirtual.
51) Destructors, deallocation, and swap never fail.
52) Copy and destroy consistently.
53) Explicitly enable or disable copying.
54) Avoid slicing. Consider Clone instead of copying in base classes.
55) Prefer the canonical form of assignment.
56) Whenever it makes sense, provide a no-fail swap (and provide it correctly).
*/
// G. Namespaces and Modules.
// 57) Keep a type and its nonmember function interface in the same namespace.
// 58) Keep types and functions in separate namespaces unless they're specifically intended to work together.
// 59) Don't write namespace usings in a header file or before an #include.
if ( keyword("using") ) {
if ( lin_header )
CCS_G( 59, "Don't write namespace usings in a header file or before an #include" );
}
/*
60) Avoid allocating and deallocating memory in different modules.
61) Don't define entities with linkage in a header file.
62) Don't allow exceptions to propagate across module boundaries.
63) Use sufficiently portable types in a module's interface.
64) Blend static and dynamic polymorphism judiciously.
65) Customize intentionally and explicitly.
66) Don't specialize function templates.
67) Don't write unintentionally nongeneric code.
H. Templates and Genericity.
68) Assert liberally to document internal assumptions and invariants.
69) Establish a rational error handling policy, and follow it strictly.
70) Distinguish between errors and non-errors.
71) Design and write error-safe code.
72) Prefer to use exceptions to report errors.
73) Throw by value, catch by reference.
74) Report, handle, and translate errors appropriately.
75) Avoid exception specifications.
I. Error Handling and Exceptions.
76) Use vector by default. Otherwise, choose an appropriate container.
77) Use vector and string instead of arrays.
78) Use vector (and string::c_str) to exchange data with non-C++ APIs.
79) Store only values and smart pointers in containers.
80) Prefer push_back to other ways of expanding a sequence.
81) Prefer range operations to single-element operations.
82) Use the accepted idioms to really shrink capacity and really erase elements.
J. STL: Containers.
83) Use a checked STL implementation.
84) Prefer algorithm calls to handwritten loops.
85) Use the right STL search algorithm.
86) Use the right STL sort algorithm.
87) Make predicates pure functions.
88) Prefer function objects over functions as algorithm and comparer arguments.
89) Write function objects correctly.
K. Type Safety.
90) Avoid type switching; prefer polymorphism.
91) Rely on types, not on representations.
92) Avoid using reinterpret_cast.
93) Avoid using static_cast on pointers.
94) Avoid casting away const.
*/
// 95) Don't use C-style casts.
if ( op_cast ) {
CCS_K( 95, "Don't use C-style casts." );
}
/*
96) Don't memcpy or memcmp non-PODs.
*/
if ( idn_function ) {
//DEBI("IF")
if ( CMPPREVTOK("memcpy") || CMPPREVTOK("memcmp") ) {
CCS_K( 96, "Don't memcpy or memcmp non-PODs." );
}
}
// 97) Don't use unions to reinterpret representation.
if ( idn_member ) {
//warn( 97, "IM %s %d", tag_name(), idn_base );
if ( strncmp( tag_name(), "", MAXIDLEN )==0 ) {
CCS_K( 97, "Don't use unions to reinterpret representation." );
}
}
/*
98) Don't use varargs (ellipsis).
*/
if ( dcl_3dots ) {
CCS_K( 98, "Don't use varargs (ellipsis)." );
}
/*
99) Don't use invalid objects. Don't use unsafe functions.
*/
if ( idn_function ) {
if ( strcmp(idn_name(),"strcpy")== 0
|| strcmp(idn_name(),"strncpy")== 0
|| strcmp(idn_name(),"sprintf")== 0 )
{
CCS_K( 99, "Don't use invalid objects. Don't use unsafe functions." );
}
}
/*
100) Don't treat arrays polymorphically.
*/
// END OF RULE-FILE CCS
// CodeCheck (c) 2005 Rule-File for C++ Coding Standard Abraxas Software
// CodeCheck (c) 2005 Rule-File for C++ Coding Standard Abraxas Software
// CodeCheck (c) 2005 Rule-File for C++ Coding Standard Abraxas Software [ CCS.CC ] // CodeCheck Rule-File to automate "C++ Coding Standards" text by Alexandrescu & Sutter #include "ccs.cch" /* This rule file has two purposes. The first is to help find problems documented in the CCS book. The second purpose is show people how to write CodeCheck rule-files. If you study the below CC source you'll see many DEBD() [ccdebug.cch] statements that have been commented out, if you remove the comments then you can generate diagnostics to learn what codecheck is actually doing. This large rule-file ccs.cc is really just an example of a rule-file system. In actuality many of these rule's should be ran as individuals because many of the rule's in fact many diagnostics and the entire system ran as ccs.cc generates too much data on real production code. */ // BEGIN OF RULE-FILE CCS /* A. Organizational and Policy Issues. 0) Don't sweat the small stuff. (Or: Know what not to standardize.). 1) Compile cleanly at high warning levels. 2) Use an automated build system. 3) Use a version control system. 4) Invest in code reviews. B. Design Style. 5) Give one entity one cohesive responsibility. 6) Correctness, simplicity, and clarity come first. 7) Know when and how to code for scalability. 8) Don't optimize prematurely. 9) Don't pessimize prematurely. 10) Minimize global and shared data. 11) Hide information. 12) Know when and how to code for concurrency. 13) Ensure resources are owned by objects. Use explicit RAII and smart pointers. */ // C. Coding Style. // 14) Prefer compile- and link-time errors to run-time errors. // 15) Use const proactively. if ( dcl_parameter ) { //DEBDL("DP") if ( dcl_level_flags(0) & CONST_FLAG ) { CCS_C( 15, "Use const proactively." ); } } // 16) Avoid macros. // warn on use of macros if ( lex_macro_token ) { CCS_C( 16, "Avoid macro - Usage." ); } // warn on definition of macros if ( lin_preprocessor ) { //warn(16, "LP %d", lin_preprocessor ); if ( lin_preprocessor == DEFINE_PP_LIN ) { CCS_C( 16, "Avoid macro - Definition." ); } } // 17) Avoid magic numbers. if ( lex_constant ) { //warn( 17, "LC %d k%d", lex_constant, tag_kind ); // verifty raw # and not within a tag { enum, class, ... } if ( lex_macro_token == 0 && tag_kind == 0 && isdigit(token()[0]) ) { CCS_C( 17, "Avoid magic numbers." ); } } // 18) Declare variables as locally as possible. /* The theory here is two problems, NOT only the decl, but the usage, the usage of the global is important, .e.g. if you mission is to fix code. Before you mod the decl, you need to know what your effecting. */ if ( dcl_variable ) { if ( dcl_global && lin_within_namespace == 0 ) { CCS_C( 18, "Declare variables as locally as possible. [ declaration ]" ); } } if ( idn_variable ) { if ( idn_global ) { CCS_C( 18, "Declare variables as locally as possible. [ usage ]" ); } } // 19) Always initialize variables. // trigger on the case of a non-init being used. if ( idn_no_init ) { CCS_C( 19, "Always initialize variables - usage." ); } // trigger on the case of a declare without an init if ( dcl_variable ) { //warn( 19, "DL %s di%d", dcl_name(), dcl_initializer ) ; if ( dcl_initializer == 0 && dcl_simple ) { CCS_C( 19, "Always initialize variables - declare." ); } } // 20) Avoid long functions. Avoid deep nesting. int deep_nest; if ( fcn_begin ) { deep_nest = 0; } if ( op_open_brace ) { ++deep_nest; if ( deep_nest > NEST_DEPTH ) { CCS_C( 20, "Avoid long functions. Avoid deep nesting. [ DEEP_NEST ]" ); } } if ( op_close_brace ) { --deep_nest; } if ( fcn_end ) { if ( fcn_total_lines > LONGFUNC ) { CCS_C( 20, "Avoid long functions. Avoid deep nesting. [ LONGFUNC ]" ); } if ( fcn_decisions > MILLER_NUM ) { CCS_C( 20, "Avoid long functions. Avoid deep nesting. [ MILLER_NUM ]" ); } } /* 21) Avoid initialization dependencies across compilation units. */ if ( dcl_variable ) { if ( lin_within_namespace ) { CCS_C( 21, "Avoid initialization dependencies across compilation units." ); } } // 22) Minimize definitional dependencies. Avoid cyclic dependencies. int type; if ( dcl_member ) { if ( lin_within_class && lin_source ) { // set idn_filename() to class-name, rather than member-name type = find_root( dcl_base_name() ); //warn( 22, "B:%s t%d C:%s t%d", dcl_base_name(), dcl_base, class_name(), type ); if ( type && dcl_simple == 0 ) { if ( strncmp(file_name(),idn_filename(),BIGIDLEN) ) { CCS_C( 22, "Minimize definitional dependencies. Avoid cyclic dependencies." ); } } } } // 23) Make header files self-sufficient. if ( lin_preprocessor ) { if ( lin_header && lin_header == PRJ_HEADER ) { //warn( 23, "LP-LH %d", lin_preprocessor ); if ( lin_preprocessor == INCLUDE_PP_LIN ) { CCS_C( 23, "Make header files self-sufficient." ); } } } // 24) Always write internal #include guards. Never write external #include guards. int guard_seen; char wrapper_name[MAXIDLEN+1]; if ( lin_preprocessor ) { //warn(24, "LP %d %s gs=%d", lin_preprocessor, pp_name(), guard_seen ); switch ( lin_preprocessor ) { case INCLUDE_PP_LIN: if ( guard_seen ) guard_seen = 0; else guard_seen = -1; break ; case IFNDEF_PP_LIN: // #ifndef if ( guard_seen < 0 ) { guard_seen = lin_number; strncpy( wrapper_name, pp_name(), MAXIDLEN ); } break; case DEFINE_PP_LIN: // #define if ( strncmp(pp_name(),wrapper_name,MAXIDLEN)==0 && (guard_seen+1) == lin_number ) { //warn( 24, "CORRECT"); } else { CCS_C( 24, "Always write internal #include guards." ); } guard_seen = 0; break; default: // catch all case, empty headers ... external if ( guard_seen ) { CCS_C( 24, "Always write internal #include guards." ); } guard_seen = 0; // done break; } } // D. Functions and Operators. //25) Take parameters appropriately by value, (smart) pointer, or reference. if ( dcl_parameter ) { if ( dcl_base == CLASS_TYPE ) { if ( dcl_level(0) != REFERENCE ) { CCS_D( 25, "Take parameters appropriately by value, (smart) pointer, or reference." ); } } } /* 26) Preserve natural semantics for overloaded operators. */ if ( op_open_funargs ) { if ( lin_within_class && strncmp(op_function(),"operator",8)==0 ) { if ( strchr(op_function(),'+') || strchr(op_function(),'*') ) { CCS_D( 26, "Preserve natural semantics for overloaded operators."); } } } /* 27) Prefer the canonical forms of arithmetic and assignment operators. */ if ( op_open_funargs ) { if ( (strncmp(op_function(),"operator",8)==0) && (strlen(token())==1) ) { strcpy( TEMPBUF, op_function() ); // find operator@ strcat( TEMPBUF, "=" ); // append operator@= // If an operator@ is seen then verify that the operator@= case is in class if ( lin_within_class==0 && find_scoped_root( dcl_base_name(),TEMPBUF ) == 0 ) { CCS_D( 27, "Prefer the canonical forms of arithmetic and assignment operators." ); } } } /* 28) Prefer the canonical form of ++ and --. Prefer calling the prefix forms. */ /* 29) Consider overloading to avoid implicit type conversions. */ // 30) Avoid overloading &&, ||, or , (comma). if ( dcl_function ) { //warn(30, "DF %s %d", fcn_name(), dcl_base ); if ( lin_within_class && strncmp(dcl_name(),"operator",8)==0 ) { if ( strstr(dcl_name(),"&&") || strstr(dcl_name(),"||") || strstr(dcl_name(),",") ) { CCS_D( 30, "Avoid overloading &&, ||, or , (comma)."); } } } // 31) Don't write code that depends on the order of evaluation of function arguments. char pidn_name[MAXIDLEN+1]; if ( op_open_funargs ) { pidn_name[0] = 0; } if ( op_pre_incr ) { if ( incall ) { if ( strncmp(idn_name(),pidn_name,MAXIDLEN)==0 ) { CCS_D( 31, "Don't write code that depends on the order of evaluation of function arguments." ); } strncpy( pidn_name, idn_name(), MAXIDLEN ); } } if ( op_return ) { if ( strstr(next_token(),"++") ) { CCS_D( 31, "Don't write code that depends on the order of evaluation of function arguments." ); } } // E. Class Design and Inheritance. /* 32) Be clear what kind of class you're writing. */ // 33) Prefer minimal classes to monolithic classes. if ( tag_end && tag_kind==CLASS_TAG ) { i = 5; while ( i>=0 ) { //warn( 33, "TE %d c%d", i, tag_components(i,0) ); if ( tag_components(i,0) > MILLER_NUM ) { CCS_E( 33, "Prefer minimal classes to monolithic classes." ); i = 0; // issue first message seen only } i--; }; } /* 34) Prefer composition to inheritance. */ if ( dcl_access_adjust ) { //warn(342, "DAA %s::%s da=%d tba=%d", dcl_scope_name(), dcl_name(), dcl_access, tag_base_access ); CCS_E( 34, "Prefer composition to inheritance." ); } /* 35) Avoid inheriting from classes that were not designed to be base classes. */ // 36) Prefer providing abstract interfaces. int pureseen; if ( tag_begin ) { if ( tag_kind == CLASS_TAG ) { pureseen = 0; } } if ( tag_end ) { if ( tag_kind == CLASS_TAG ) { //warn(36,"TE p=%d tb=%d", pureseen, tag_bases ); if ( tag_bases == 0 && pureseen == 0 ) { CCS_E( 36, "Prefer providing abstract interfaces." ); } pureseen = 0; } } if ( dcl_pure ) { pureseen = lin_number; } /* 37) Public inheritance is substitutability. Inherit, not to reuse, but to be reused. */ // 38) Practice safe overriding. int initzero; if ( tag_begin ) { initzero = lin_number; } if ( dcl_parameter ) { if ( isdigit(prev_token()[0]) ) { if ( atoi( prev_token() ) == 0 ) { initzero = lin_number ; } } } if ( dcl_virtual ) { //warn( 38, "DV %s iz=%d", dcl_name(), initzero ); if ( initzero != lin_number ) { CCS_E( 38, "Practice safe overriding." ); } } /* 39) Consider making virtual functions nonpublic, and public functions nonvirtual. */ if ( dcl_function ) { //warn(39, "%s %s dff=%d da=%d", class_name(), dcl_name(), dcl_function_flags, dcl_access ); if ( dcl_member ) { if ( dcl_access == PUBLIC_ACCESS && dcl_function_flags & VIRTUAL_FCN ) { CCS_E( 39, "Consider making virtual functions nonpublic" ); } else if ( dcl_access != PUBLIC_ACCESS && (dcl_function_flags & VIRTUAL_FCN)==0 ) { CCS_E( 39, "Consider making non-virtual functions public" ); } } } /* 40) Avoid providing implicit conversions. */ if ( dcl_function ) { // warn(40, "DF %s f%d", dcl_name(), dcl_function_flags ); if ( dcl_function_flags & OPERATOR_FCN ) { if ( dcl_base >= VOID_TYPE && dcl_base < ENUM_TYPE ) { // primitive type's CCS_E( 40, "Avoid providing implicit conversions." ); } } } /* 41) Make data members private, except in behaviorless aggregates (C-stylestructs). */ if ( dcl_member ) { //warn( 41, "DM %s dm%d a%d b%d", dcl_name(), dcl_member, dcl_access, dcl_base ); if ( dcl_access == PUBLIC_ACCESS && ( dcl_base == CLASS_TYPE || dcl_base < ENUM_TYPE ) ) { CCS_E( 41, "Make data members private, except in behaviorless aggregates" ); } } // 42) Don't give away your internals. // 43) Pimpl judiciously. // 44) Prefer writing nonmember nonfriend functions. // 45) Always provide new and delete together. // 46) If you provide any class-specific new, provide all of the standard forms (plain, in-place, and nothrow). // F. Construction, Destruction, and Copying. /* 47) Define and initialize member variables in the same order. 48) Prefer initialization to assignment in constructors. 49) Avoid calling virtual functions in constructors and destructors. 50) Make base class destructors public and virtual, or protected and nonvirtual. 51) Destructors, deallocation, and swap never fail. 52) Copy and destroy consistently. 53) Explicitly enable or disable copying. 54) Avoid slicing. Consider Clone instead of copying in base classes. 55) Prefer the canonical form of assignment. 56) Whenever it makes sense, provide a no-fail swap (and provide it correctly). */ // G. Namespaces and Modules. // 57) Keep a type and its nonmember function interface in the same namespace. // 58) Keep types and functions in separate namespaces unless they're specifically intended to work together. // 59) Don't write namespace usings in a header file or before an #include. if ( keyword("using") ) { if ( lin_header ) CCS_G( 59, "Don't write namespace usings in a header file or before an #include" ); } /* 60) Avoid allocating and deallocating memory in different modules. 61) Don't define entities with linkage in a header file. 62) Don't allow exceptions to propagate across module boundaries. 63) Use sufficiently portable types in a module's interface. 64) Blend static and dynamic polymorphism judiciously. 65) Customize intentionally and explicitly. 66) Don't specialize function templates. 67) Don't write unintentionally nongeneric code. H. Templates and Genericity. 68) Assert liberally to document internal assumptions and invariants. 69) Establish a rational error handling policy, and follow it strictly. 70) Distinguish between errors and non-errors. 71) Design and write error-safe code. 72) Prefer to use exceptions to report errors. 73) Throw by value, catch by reference. 74) Report, handle, and translate errors appropriately. 75) Avoid exception specifications. I. Error Handling and Exceptions. 76) Use vector by default. Otherwise, choose an appropriate container. 77) Use vector and string instead of arrays. 78) Use vector (and string::c_str) to exchange data with non-C++ APIs. 79) Store only values and smart pointers in containers. 80) Prefer push_back to other ways of expanding a sequence. 81) Prefer range operations to single-element operations. 82) Use the accepted idioms to really shrink capacity and really erase elements. J. STL: Containers. 83) Use a checked STL implementation. 84) Prefer algorithm calls to handwritten loops. 85) Use the right STL search algorithm. 86) Use the right STL sort algorithm. 87) Make predicates pure functions. 88) Prefer function objects over functions as algorithm and comparer arguments. 89) Write function objects correctly. K. Type Safety. 90) Avoid type switching; prefer polymorphism. 91) Rely on types, not on representations. 92) Avoid using reinterpret_cast. 93) Avoid using static_cast on pointers. 94) Avoid casting away const. */ // 95) Don't use C-style casts. if ( op_cast ) { CCS_K( 95, "Don't use C-style casts." ); } /* 96) Don't memcpy or memcmp non-PODs. */ if ( idn_function ) { //DEBI("IF") if ( CMPPREVTOK("memcpy") || CMPPREVTOK("memcmp") ) { CCS_K( 96, "Don't memcpy or memcmp non-PODs." ); } } // 97) Don't use unions to reinterpret representation. if ( idn_member ) { //warn( 97, "IM %s %d", tag_name(), idn_base ); if ( strncmp( tag_name(), "", MAXIDLEN )==0 ) { CCS_K( 97, "Don't use unions to reinterpret representation." ); } } /* 98) Don't use varargs (ellipsis). */ if ( dcl_3dots ) { CCS_K( 98, "Don't use varargs (ellipsis)." ); } /* 99) Don't use invalid objects. Don't use unsafe functions. */ if ( idn_function ) { if ( strcmp(idn_name(),"strcpy")== 0 || strcmp(idn_name(),"strncpy")== 0 || strcmp(idn_name(),"sprintf")== 0 ) { CCS_K( 99, "Don't use invalid objects. Don't use unsafe functions." ); } } /* 100) Don't treat arrays polymorphically. */ // END OF RULE-FILE CCS // CodeCheck (c) 2005 Rule-File for C++ Coding Standard Abraxas SoftwarePackage Index Table of Contents
Abraxas Sofware, Inc. Home