//

// This file contains some rules which are implemenation

// of ways improving C++ programs listed in two books

// written by Scott Meyers ( "Effective C++" and "More

// Effective C++", both are published by Addison-Wesley. )

// There are 50 items listed in "Effective C++" and 35

// items in "More Effective C++.

//

 // Abraxas Software, inc. Email: info@abxsoft.com


#include <check.cch>

 

#define MAXIDNLEN 64 // assume all identifiers have maximal length of 64

#define MAXLIST 1024 // maximal length for a name list

 

// variables used frequently in rules

int i; // variable used mostly as iteration counter

int j; // other variable used mostly as iteration counter

int l; // variable used mostly for string length

char* p; // variable used as pointer to characters in a name list

char* q;

 

//

// Items 1 through 50 are listing in book "Effective C++"

//

 

////////////////////////////////////////////////////////////

//

// Item 1 : Use const and inline instead of #define.

//

 

// pp_const identifies macro defining a const.

 

if ( pp_const )

{

warn( 101, "Define %s as const instead of macro.", pp_name() );

}

 

// pp_arg_count idenifies function-like macro with argument(s).

// for example, #define PLUS( x, y ) (x) + ( y )

// pp_empty_arglist identifies function-like macro without argument.

// for example, #define X_PLUS_Y() (x) + (y)

 

// it is not recommended to invoke a rule with more than one

// triggers unless they are absolutely exclusive to each other.

//

if ( pp_arg_count || pp_empty_arglist )

{

warn( 102, "Define %s as inline instead of macro.", pp_name() );

}

 

////////////////////////////////////////////////////////////

// Item 2: Prefer iostream.h to stdio.h.

//

 

// this rule simply tells you to use "iostream.h" when "stdio.h"

// is found in #include.

 

// value 3 means header is included in a pair of brackets( <> ).

// see pp_include in master.doc for details.

 

if ( pp_include == 3 )

{

if ( !strcmp( header_name(), "stdio.h" ) )

{

warn( 201, "Prefer iostream.h to stdio.h" );

}

}

 

////////////////////////////////////////////////////////////

// Item 3 : Use new and delete instead of malloc and free.

//

 

// each time as function is called, idn_function is fired

// up, then it is decided if function "malloc" or "free"

// are called by comparing the function name against

// strings "malloc" and "free".

if ( idn_function )

{

if ( !strcmp( idn_name(), "malloc" ) )

{

warn( 301, "Use new instead of malloc.");

}

if ( !strcmp( idn_name(), "free" ) )

{

warn( 302, "Use delete instead of free.");

}

}

 

////////////////////////////////////////////////////////////

// Item 4 : Prefer C++-style comments.

//

 

// lex_c_comment is triggered by any comment included in

// /* and */

if ( lex_c_comment )

{

warn( 401, "Use C++-style comment instead of C style comment" );

}

 

////////////////////////////////////////////////////////////

// Item 5 : Use the same form in corresponding calls to

// new and delete

//

 

// Assume that all calls to new and delete are in the forms

// 1. ptr = new type;

// delete ptr;

// or

// 2. ptr = new type[ count ];

// delete [] ptr;

 

#define DELETE_WITHOUT_BRACKETS 1

#define DELETE_WITH_BRACKETS 2

 

// currently, the arrays can be used in rules are still very

// limited, only one dimensional, fixed size and of type char.

// the way to store multiple names in an array is to put them

// in sequence separated by character '\0'.

char idnName[MAXIDNLEN]; // name of a pointer

char newList1[MAXLIST]; // names of pointer in form 1

char newList2[MAXLIST]; // names of pointer in form 2

int inNew; // TRUE if operator new is used

int inDelete; // 1 if operator delete is used, 2 if operator delete[] used

int found;

 

if ( idn_variable )

{

// idn_name() returns identifier's name

strcpy( idnName, idn_name() ); // copy identifier's name to idnName

 

if ( inDelete )

{

if ( inDelete == DELETE_WITH_BRACKETS ) // in form delete [] ptr;

{

p = newList2; // search the name registered as form 2

}

else // in form delete ptr;

{

p = newList1; // search the name registered as form 1

}

 

j = 0;

found = FALSE;

while ( p[0] != 0 ) // p[0] == 0 means no more names in list

{

if ( strcmp( p, idnName ) == 0 ) // looking for the name in list

{

i = 0;

found = TRUE; // the name is found in name list

 

// name found, remove it from the list

while ( j < MAXLIST - ( strlen( idnName ) + 1 ) )

{

p[i] = p[i + strlen( idnName ) + 1];

j++;

i++;

}

break;

}

else // not found, keep looking

{

p = p + strlen( p ) + 1;

j = j + strlen( p ) + 1;

}

}

 

// name was not found in list with matching form of new.

// try the list for the other form of new.

if ( p[0] == 0 && !found )

{

if ( inDelete == DELETE_WITH_BRACKTS ) // in form delete [] ptr, try list for new type

{

p = newList1;

}

else // in form delete ptr, try list for new type[]

{

p =newList2;

}

 

found = FALSE;

j = 0;

while ( p[0] != 0 )

{

if ( strcmp( p, idnName ) == 0 )

{

found = TRUE;

 

if ( inDelete == 1 )

{

warn( 501 ,"Use form delete [] %s.", idnName );

}

else

{

warn( 502, "Use form delete %s.", idnName );

}

 

i =0;

 

// remove the found name from the other list

while ( j < MAXLIST - ( strlen( idnName ) + 1 ) )

{

p[i] = p[i + strlen( idnName ) + 1];

j++;

i++;

}

break;

}

else

{

p = p + strlen( p ) + 1;

j = j + strlen( p ) + 1;

}

}

 

// the name to be deleted not found in either list

if ( p[0] == 0 && !found )

{

warn(503, "%s has not been allocated with new yet.", idnName );

}

}

}

}

 

// found new operator

if ( op_new )

{

inNew = TRUE;

}

 

// found delete operator

if ( op_delete )

{

inDelete = DELETE_WITHOUT_BRACKETS;

}

 

// assume that new is used in a single assignment statement

// which ends with a semicolon.

if ( op_semicolon )

{

if ( inNew )

{

if ( strcmp( prev_token(), "]" ) == 0 ) // in form new type[]

{

p = newList2;

}

else // in form new type

{

p = newList1;

}

 

found = FALSE;

while ( p[0] != 0 )

{

// the name has been in list.

if ( strcmp( p, idnName ) == 0 )

{

warn( 505, "Delete %s before it is reallocated.", idnName );

found = TRUE;

break;

}

p = p + strlen( p ) + 1;

}

if ( !found )

{

i = 0;

l = strlen( idnName );

while ( i <= l )

{

p[ i ] = idnName[ i ];

i++;

}

}

inNew = FALSE;

}

if ( inDelete )

{

inDelete = 0;

}

}

 

// at the end of a module, clear both lists to all 0. before

// cleaning, see if there is any pointer name which has been

// allocated a piece of memory, but the memory is never returned.

if ( mod_end )

{

// clean up the lists

p = newList1;

while ( p[0] != 0 )

{

warn( 504, "%s was allocated with new, but never deleted in %s.", p, file_name() );

i = 0;

while ( i <= strlen( p ) )

{

p[0] = 0;

p = p + 1;

i++;

}

}

p = newList2;

while ( p[0] != 0 )

{

warn( 504, "%s was allocated with new, but never deleted in %s.", p, file_name() );

i = 0;

while ( i <= strlen( p ) )

{

p[0] = 0;

p = p + 1;

i++;

}

}

}

 

// op_open_brackets combined with inDelete and the value of

// the previous token can decide if in form delete[] ptr.

if ( op_open_bracket )

{

if ( inDelete && strcmp( prev_token(), "delete" ) == 0 )

{

inDelete = DELETE_WITH_BRACKETS; // it is in form delete [] ptr

}

}

 

////////////////////////////////////////////////////////////

// Item 6 : Call delete on pointer members in destructors.

//

 

// assume that a destructor function is defined in class

// definition.

 

int inClass; // TRUE when in a class body

int inDtor; // TRUE when in a destructor definition

int ptrMember; // the number of data members which are pointers

int delPtrMem; // those members which are explicitly deleted in destructor

 

 

// tag_begin marks the beginning of a tag starting from

// open brace.

if ( tag_begin )

{

if ( tag_kind > ENUM_TAG ) // enum is not a class

{

inClass = TRUE;

}

}

 

if ( dcl_variable )

{

if ( dcl_member )

{

if ( inClass )

{

if ( dcl_levels >= 1 ) // for a pointer, dcl_levels has value at least 1

{

i = 0;

while ( i <= dcl_levels )

{

if ( dcl_level( i ) == POINTER ) // this is a pointer

{

ptrMember++;

break;

}

i++;

}

}

}

}

}

 

if ( dcl_function )

{

if ( dcl_member )

{

if ( dcl_definition ) // this is a defintion of the destructor

{

if ( inClass )

{

if ( dcl_base == DESTRUCTOR_TYPE )

{

inDtor = TRUE;

}

}

}

}

}

 

if ( idn_variable )

{

if ( idn_member && inDelete ) // the data member is explicitly deleted in destructor

{

if ( inDtor )

{

delPtrMem++;

}

}

}

 

// at the end of a function, inDtor needs to be reset

if ( fcn_end )

{

if ( inDtor )

{

inDtor = FALSE;

}

}

 

// at the end of a tag

if ( tag_end )

{

if ( tag_kind > ENUM_TAG ) // it has to be a class

{

if ( delPtrMem < ptrMember )

{

warn( 601, "There are %d pointer members need to be deleted in destructor.", ptrMember-delPtrMem );

}

delPtrMem = 0;

inClass = FALSE;

}

}

////////////////////////////////////////////////////////////

// Item 7 : Check the return value of new.

//

 

////////////////////////////////////////////////////////////

// Item 8 : Adhere to convention when writing new.

//

 

int seeOperator; // TRUE if keyword operator is found

int setNewHandler; // TRUE if function call to set_new_handler is found

int inNewOperator; // TRUE if in defintion of operator new

 

// without this flag, it could be confusing when looking at

// value of return value of dcl_name() in next rule. because

// a function named "operator_new" has the same name as

// "operator new".

// for operators with name composed of only punctual characters

// such as "operator +", the function return value "operator+",

// if operator name is "new" or "delete", a underscore is inserted

// in between.

 

if ( keyword( "operator" ) )

{

seeOperator = TRUE;

}

 

if ( dcl_function )

{

if ( dcl_definition && seeOperator )

{

if ( strcmp( dcl_name(), "operator_new" ) == 0 )

{

// dcl_levels == 2 means the return value is not a simple type

// dcl_level( 1 ) == POINTER means it is a pointer.

if ( dcl_levels != 2 || ( dcl_levels == 2 && dcl_level( 1 ) != POINTER ) )

{

warn( 802, "Operator new should return a pointer." );

}

inNewOperator = TRUE;

}

}

seeOperator = FALSE;

}

 

// at the end of a function definition, the variables

// specifically for function need to be reset.

if ( fcn_end )

{

if ( inNewOperator )

{

if ( !setNewHandler )

{

warn( 801, "Need to call function set_new_handler" );

}

}

inNewOperator = FALSE;

setNewHandler = FALSE;

}

 

// in the definition of a operator new, function set_new_handler

// needed to called at least once.

if ( idn_function )

{

if ( inNewOperator )

{

if ( strcmp( idn_name(), "set_new_handler" ) == 0 )

{

setNewHandler = TRUE;

}

}

}

 

////////////////////////////////////////////////////////////

// Item 9 : Avoid hiding the global new.

//

 

////////////////////////////////////////////////////////////

// Item 10 : Write delete if you write new.

//

 

int definedNew; // TRUE if a class has a user defined new operator

int definedDelete; // TRUE if a class has a user defined delete operator

 

// we have seen some other rules which are also triggered

// by tag_begin. CodeCheck will concatenate all actions into

// a list. the only thing you need to be careful is that do

// not have conflicts in these actions, such as setting a

// flag here and resetting it there.

if ( tag_begin )

{

definedNew = FALSE;

definedDelete = FALSE;

}

 

 

if ( tag_end )

{

if ( definedNew )

{

if ( !definedDelete )

{

warn( 1001, "Also write delete for class %s.", tag_name() );

}

}

}

 

if ( dcl_member && dcl_function )

{

if ( !strcmp( dcl_name(), "operator_new" ) )

{

definedNew = TRUE;

}

if (!strcmp( dcl_name(), "operator_delete" ) )

{

definedDelete = TRUE;

}

}

 

////////////////////////////////////////////////////////////

// Item 11 : Define a copy constructor and an assignment

// operator for classes with dynamically

// allocated memory.

//

 

if ( tag_end )

{

if ( ptrMember ) // ptrMember has been set at previous rule

{

if ( !tag_has_copy )

{

warn( 1101, "Class %s needs an explicit copy constructor.", tag_name() );

}

if ( !tag_has_assign )

{

warn( 1102, "Class %s needs an explicit assignment operator.", tag_name() );

}

}

ptrMember = 0; // ptrMember has been cleared somewhere else, however this repetition is harmless

}

 

////////////////////////////////////////////////////////////

// Item 12 : Prefer initialization to assignment in

// constructors.

//

 

char dataMembers[MAXLIST]; // the list of all data members of a class

char ctorInitList[MAXLIST]; //

int angleLevel;

int parenLevel;

int inCtorInit;

 

if ( tag_begin )

{

p = dataMembers;

i = 0;

while ( i < MAXLIST ) // clear both lists to all zero

{

dataMembers[i] = 0;

ctorInitList[i] = 0;

i++;

}

}

 

// record all the data members of a class

if ( dcl_variable )

{

if ( dcl_member )

{

if ( inClass )

{

i = 0;

while ( i <= strlen( dcl_name() ) )

{

p[i] = dcl_name()[i];

i++;

}

p = p + 1;

}

}

}

 

if ( dcl_function )

{

if ( dcl_definition )

{

if ( inClass )

{

if ( dcl_base == CONSTRUCTOR_TYPE )

{

inCtorInit = TRUE;

p = dataMembers;

i = 0;

while ( p[ 0 ] != 0 )

{

q = ctorInitList;

j = 0;

while ( q[ 0 ] != 0 )

{

if ( strcmp( p, q ) == 0 )

{

break;

}

else

{

q = q +strlen( q ) + 1;

j++;

}

}

if ( q[ 0 ] == 0 )

{

warn( 1201, "Put data member %s in contructor initializer list.", p );

}

else

{

if ( i != j )

{

warn( 1301, "Data member %s is not in the same order in the declaration list.", p );

}

}

p = p + strlen( p ) +1;

i++;

}

}

}

}

}

 

if ( op_init )

{

if ( inClass )

{

inCtorInit = TRUE;

parenLevel = 0;

p = ctorInitList;

}

}

 

if ( op_open_paren )

{

if ( inCtorInit )

{

if ( parenLevel == 0 )

{

i = 0;

while ( i <= strlen( prev_token() ) )

{

p[ i ] = prev_token()[ i ];

i++;

}

p = p + 1;

}

parenLevel++;

}

}

 

if ( op_close_paren )

{

if ( inCtorInit )

{

parenLevel--;

}

}

 

////////////////////////////////////////////////////////////

// Item 13 : List members in an initialization list in the

// order in which they are declared.

//

 

////////////////////////////////////////////////////////////

// Item 14 : Make destructors virtual in base class.

//

 

int isBaseClass; // TRUE if we are in a base class definition

int inBase; // TRUE if we are in the base class declaration

int inClassHead; // TRUE is we in the class header

char tagList[MAXLIST];

 

// this rule will be invoked for any member function declared as virtual

if ( dcl_virtual )

{

if ( dcl_base == DESTRUCTOR_TYPE ) // see if this a destructor declaration

{

// if a class has a virtual destructor, keep its name in list

if ( tagList[0] == 0 ) // there is no name in list yet

{

i = 0;

while ( i <= strlen( tag_name() ) )

{

tagList[i] = tag_name()[i];

i++;

}

}

else // put this class name at the end of the list

{

p = tagList;

while ( 1 )

{

if ( p[0] == 0 )

{

i = 0;

while ( i <= strlen( tag_name() ) )

{

p[i] = tag_name()[i];

i++;

}

break;

}

else

{

p = p + strlen( p ) +1;

}

}

}

}

}

 

if ( keyword( "class" ) )

{

if ( strcmp( prev_token(), "<" ) != 0 )

{

inClassHead = TRUE;

}

}

 

if ( op_colon_1 )

{

if ( inClassHead )

{

inBase = TRUE;

}

}

 

if ( op_separator )

{

if ( inBase )

{

if ( strcmp( prev_token(), ">" ) != 0 )

{

isBaseClass = TRUE;

}

}

}

 

if ( op_open_angle )

{

if ( inBase )

{

if ( angleLevel == 0 )

{

isBaseClass = TRUE;

}

angleLevel++;

}

}

 

if ( op_close_angle )

{

if ( inBase )

{

angleLevel--;

if ( angleLevel == 0 )

{

isBaseClass = FALSE;

}

}

}

 

if ( isBaseClass )

{

p = tagList;

while ( p[ 0 ] != 0 )

{

if (strcmp( p, prev_token() ) == 0 )

{

break;

}

else

{

p = p + strlen( p ) + 1;

}

}

if ( p[ 0 ] == 0 )

{

warn( 1401, "The destructor of class %s should be declared as virtual.", tag_name() );

}

}

 

if ( tag_begin )

{

inBase = FALSE;

inClassHead = FALSE;

}

 

////////////////////////////////////////////////////////////

// Item 15 : Have operator= return a reference to *this.

//

int inOpAssign; // TRUE if we are in function body for operator =

int rightForm; // TRUE if the return *this found

int inReturn; // TRUE if in return statement which is in operator =

 

if ( dcl_member )

{

if ( dcl_function && dcl_definition )

{

if ( strcmp( dcl_name(), "operator=" ) == 0 )

{

inOpAssign = TRUE;

}

}

}

 

if ( op_return ) // keyword return found

{

if ( inOpAssign )

{

inReturn = TRUE; // now, we are in a returning statement

}

}

 

// we need to see return *this;

if ( keyword( "this" ) )

{

if ( inReturn )

{

if ( strcmp( prev_token(), "*" ) == 0 )

{

rightForm =TRUE ;

}

}

}

 

if ( stm_end )

{

if ( stm_kind == RETURN )

{

if ( !rightForm )

{

warn( 1501, "Return a reference to *this." );

}

}

rightForm = FALSE;

inReturn = FALSE;

}

 

if ( fcn_end )

{

inOpAssign = FALSE;

}

 

////////////////////////////////////////////////////////////

// Item 16 : Assign to all data members in operator=.

 

////////////////////////////////////////////////////////////

// Item 17 : Check for assignment to self in operator=.

//

/*

if ( dcl_parameter )

{

i = 0;

while ( i <= strlen( dcl_name() )

{

paramName[ i ] = dcl_name()[ i ];

i++;

}

}

 

if ( op_if )

{

if ( inOpAssign )

{

inIfCond = 1;

}

}

 

if ( op_open_paren )

{

if ( inIfCond )

{

parenLevel++;

}

}

 

if ( op_close_paren )

{

if ( inIfCond )

{

parenLevel--;

}

if ( parenLevel == 0 )

{

inIfCond = 0;

}

}

*/

 

////////////////////////////////////////////////////////////

// Item 18 : Strive for class interfaces that are complete

// and minimal.

//

 

////////////////////////////////////////////////////////////

// Item 19 : Differentiate among member functions, gloabl

// functions, and friend functions.

//

 

////////////////////////////////////////////////////////////

// Item 20 : Avoid data members in public interface.

//

 

if ( dcl_member )

{

if ( dcl_variable )

{

if ( dcl_access == PUBLIC_ACCESS )

{

warn( 2001, "Data member %s should not be in public interface.", dcl_name() );

}

}

}

 

////////////////////////////////////////////////////////////

// Item 21 : Use const whenever possible.

//

 

////////////////////////////////////////////////////////////

// Item 22 : Pass and return objects by reference instead

// of by value.

//

 

if ( dcl_function )

{

// for function returning dcl_level has value at least 1,

// 0 for simple value type, 1 for function return itself.

// see details of dcl_level in master.doc.

 

// assume only class objects are subject to the rule, because

// copying a simple variable such as an integer is not expensive

// than passing the address.

if ( dcl_levels == 1 && dcl_base <= CLASS_TYPE && dcl_base >= UNION_TYPE )

{

warn( 2201, "Return objects by reference instead of by value." );

}

}

 

if ( dcl_parameter )

{

if ( dcl_levels == 0 && dcl_base <= CLASS_TYPE && dcl_base >= UNION_TYPE )

{

warn( 2202, "Pass objects by reference instead of by value." );

}

}

 

////////////////////////////////////////////////////////////

// Item 23 : Don't try to return a reference when you must

// return an object.

//

 

////////////////////////////////////////////////////////////

// Item 24 : Choose carefully between function overloading

// and parameter defaulting.

//

 

////////////////////////////////////////////////////////////

// Item 25 : Avoid overloading on a pointer and a numerical

// type.

//

////////////////////////////////////////////////////////////

// Item 26 : Guard against potential ambiguity.

//

 

////////////////////////////////////////////////////////////

// Item 27 : Explicitly disallow use of implicitly

// generated member functions you don't want.

//

 

////////////////////////////////////////////////////////////

// Item 28 : Use structs to partition the global namespace.

//

 

////////////////////////////////////////////////////////////

// Item 29 : Avoid returning "handles" to internal data

// from const member functions.

//

 

////////////////////////////////////////////////////////////

// Item 30 : Avoid member functions that return pointers or

// references to members less accessible than

// themselves.

//

 

// Need idn_access to get if a member is a public, private or

// protected.

 

////////////////////////////////////////////////////////////

// Item 31 : Never return a reference to a local object or

// a deferenced pointer initialized by new within

// the function.

//

 

int fcnNeedAttn; // TRUE the function returns a reference to an object

int inRtrn; // TRUE if the return is in the specific functions.

 

if ( dcl_function )

{

if ( dcl_definition )

{

// we re looking functions which is declared as

// type &func()

// here dcl_level(0) is for function and dcl_level(1)

// is for reference.

if ( dcl_levels == 2 && dcl_level( 0 ) == FUNCTION && dcl_level ( 1 ) == REFERENCE )

{

 

fcnNeedAttn = TRUE; // this is function we need to pay attentions

}

}

}

 

// we have seen op_return used as rule trigger before this,

// however, the restrictions are different, so we use the

// other name for marking being in return statement.

if ( op_return )

{

if ( fcnNeedAttn )

{

inRtrn = TRUE;

}

}

 

// this rule check if the local variable is returned

// for the kind functions we are paying attention.

if ( idn_variable )

{

if ( inRtrn ) // screen out the return statements not in these functions

{

if ( idn_local ) // this rule only cares about local variables

{

if ( idn_levels == 0 )

{

warn( 3101, "Do not return a reference to local object." );

}

}

}

}

 

// at the end of a statement, clear inRtrn to FALSE

if ( stm_end )

{

inRtrn = FALSE;

}

 

////////////////////////////////////////////////////////////

// Item 32 : Use enum for integral class constants.

//

 

if ( lex_constant == CONST_INTEGER )

{

if ( lin_within_class )

{

warn( 3201, "Use enum for integral class constant." );

}

}

 

////////////////////////////////////////////////////////////

// Item 33 : Use inlining judiciously.

//

 

////////////////////////////////////////////////////////////

// Item 34 : Minimize compilation dependencies between

// files.

//

 

////////////////////////////////////////////////////////////

// Item 35 : Make sure public inheritance models "isa".

//

 

////////////////////////////////////////////////////////////

// Item 36 : Differentiate between inheritance of interface

// and inheritance of implementation.

//

 

////////////////////////////////////////////////////////////

// Item 37 : Never redefine an inherited nonvirtual

// function.

//

 

////////////////////////////////////////////////////////////

// Item 38 : Never redefine an inherited default parameter

// value.

 

////////////////////////////////////////////////////////////

// Item 39 : Avoid cast down the inheritance hierarchy.

//

 

////////////////////////////////////////////////////////////

// Item 40 : Model "has-a" or "is-implemented-in-term-of"

// through layering.

//

 

////////////////////////////////////////////////////////////

// Item 41 : Use private inheritance judiciously.

//

 

////////////////////////////////////////////////////////////

// Item 42 : Differentiate between inheritance and

// templates.

 

////////////////////////////////////////////////////////////

// Item 43 : Use multiple inheritance judiciously.

//

 

////////////////////////////////////////////////////////////

// Item 44 : Say what you mean; understand what you're

// saying.

//

 

////////////////////////////////////////////////////////////

// Item 45 : Know what functions C++ silently writes and

// calls

//

 

////////////////////////////////////////////////////////////

// Item 46 : Prefer compile-time and link-time errors to

// run time errors.

//

 

////////////////////////////////////////////////////////////

// Item 47 : Ensure that global objects are initialized

// before they are used.

//

 

// an object is initialized either as

// type_name x = init;

// or

// class_name x( init );

//

// in either cases, op_init will triggered before dcl_global

// is triggered.

 

int seeInitOp; // TRUE if is a initialization opertor has been found.

if ( dcl_global )

{

// dcl_definition excludes the variable declared with explicit extern.

if ( dcl_variable && dcl_definition )

{

if ( !seeInitOp )

{

warn( 4701, "%s needs to be initialized.", dcl_name() );

}

seeInitOp = FALSE; // reset seeInitOp for next declarator

}

}

 

// most triggers are cleared right after prasing moving on. so it is

// necessary to set the value seeInitOp to TRUE to remember this

// initializing operator, otherwise, when dcl_global is triggered,

// op_init has been reset to 0 again.

if ( op_init )

{

seeInitOp = TRUE; // set seeInitOp for current declarator

}

 

////////////////////////////////////////////////////////////

// Item 48 : Pay attention to compiler warnings.

//

 

////////////////////////////////////////////////////////////

// Item 49 : Plan for coming language features.

//

 

////////////////////////////////////////////////////////////

// Item 50 : Read ARM.

//

 

//

// Item 51 to item 85 are listed in book "More Effective

// C++" as item 1 to item 35.

//

 

////////////////////////////////////////////////////////////

// Item 51 : Distinguish between pointers and references.

//

 

////////////////////////////////////////////////////////////

// Item 52 : Prefer C++-style casts.

//

 

if ( op_cast )

{

warn( 5201, "Use C++ style cast." );

}

 

////////////////////////////////////////////////////////////

// Item 53 : Never treat arrays polymorphically.

//

 

////////////////////////////////////////////////////////////

// Item 54 : Avoid gratuitous default constructors.

//

 

////////////////////////////////////////////////////////////

// Item 55 : Be wary of user-defined conversion functions.

//

 

////////////////////////////////////////////////////////////

// Item 56 : Distinguish between prefix and postfix forms

// of increment and decrememnt operators.

//

 

////////////////////////////////////////////////////////////

// Item 57 : Never overload &&, ||, or ,.

//

 

if ( dcl_member )

{

if ( dcl_function )

{

if ( strcmp( dcl_name(), "operator&&" ) == 0 )

{

warn( 5701, "Do not overload operator &&." );

}

else

{

if ( strcmp( dcl_name(), "operator||" ) == 0 )

{

warn( 5702, "Do not overload operator ||." );

}

else

{

if ( strcmp( dcl_name(), "operator," ) == 0 )

{

warn( 5703, "Do not overload operator ,." );

}

}

}

}

}

 

////////////////////////////////////////////////////////////

// Item 58 : Understand the difference meanings of new and

// delete.

//

 

////////////////////////////////////////////////////////////

// Item 59 : Use destructors to prevent resource leaks.

//

 

////////////////////////////////////////////////////////////

// Item 60 : Prevent resource leak in constructors.

//

 

////////////////////////////////////////////////////////////

// Item 61 : Prevent exceptions from leaving destructors.

//

 

////////////////////////////////////////////////////////////

// Item 62 : Understand how throwing an exception differs

// from passing a parameter or calling a virtual

// function.

//

 

////////////////////////////////////////////////////////////

// Item 63 : Catch exceptions by reference.

//

 

////////////////////////////////////////////////////////////

// Item 64 : Use exception specifications judiciously.

//

 

////////////////////////////////////////////////////////////

// Item 65 : Understand the costs of exception handling.

//

 

////////////////////////////////////////////////////////////

// Item 66 : Remember the 80-20 rule.

//

 

////////////////////////////////////////////////////////////

// Item 67 : Consider using lazy evaluation

//

 

////////////////////////////////////////////////////////////

// Item 68 : Amortize the cost of expected computations.

//

 

////////////////////////////////////////////////////////////

// Item 69 : Understand the origin of temporary objects.

//

 

////////////////////////////////////////////////////////////

// Item 70 : Facilitate the return value of optimization.

//

 

////////////////////////////////////////////////////////////

// Item 71 : Overload to avoid implicit type conversions.

//

 

////////////////////////////////////////////////////////////

// Item 72 : Consider using op= instead of stand-alone op.

//

/*

int opAdd;

int opAddAssign;

 

if ( tag_begin )

{

opAdd = 0;

opAddAssign = 0;

opSub = 0;

opSubAssign = 0;

opMul = 0;

opMulAssign = 0;

opDiv = 0;

opDivAssign = 0;

}

 

if ( dcl_member )

{

if ( dcl_function )

{

if ( strstr( dcl_name(), "operator" ) == dcl_name() )

{

p = p + 8;

if ( p[ strlen( p ) - 1 ] == '=' && p [ 0 ] != '=' )

{

switch ( p[ 0 ] )

{

case '+' :

opAddAssign = 1;

break;

case '-' :

opSubAssign = 1;

break;

case '*' :

opMulAssign = 1;

break;

case '/' :

opDivAssign = 1;

}

}

if ( p[

*/

 

////////////////////////////////////////////////////////////

// Item 73 : Consider alternative libraries.

//

 

////////////////////////////////////////////////////////////

// Item 74 : Understand the costs of virtual functions,

// multiple inheritance, virtual base classes,

// and RTTI.

//

 

// 1. Do not inline virtual function.

if ( dcl_function )

{

if ( dcl_virtual && dcl_inline )

{

warn( 2401, "Do not inline virtual function %s.", dcl_name() );

}

}

 

////////////////////////////////////////////////////////////

// Item 75 : Virtualizing constructors and non-member

// functions.

//

 

////////////////////////////////////////////////////////////

// Item 76 : Limiting of objects of a class.

//

 

////////////////////////////////////////////////////////////

// Item 77 : Requiring or prohibiting heap-based objects.

//

 

////////////////////////////////////////////////////////////

// Item 78 : Smart pointers.

//

 

////////////////////////////////////////////////////////////

// Item 79 : Reference counting.

//

 

////////////////////////////////////////////////////////////

// Item 80 : Proxy classes.

//

 

////////////////////////////////////////////////////////////

// Item 81 : Making functions virtual with respect to more

// than one object.

//

 

////////////////////////////////////////////////////////////

// Item 82 : Program in future tense.

//

 

////////////////////////////////////////////////////////////

// Item 83 : Make non-leaf classes abstract.

//

 

////////////////////////////////////////////////////////////

// Item 84 : Understand how to combine C++ and C in the

// same program.

//

 

////////////////////////////////////////////////////////////

// Item 85 : Familiarize yourself with the language

// standard.

//

 

// End of Rule file.