//
// 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.