diff -r 000000000000 -r 83f4b4db085c srcanamdw_os/leavescan/source/leavescan.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/srcanamdw_os/leavescan/source/leavescan.cpp Tue Feb 02 01:39:43 2010 +0200 @@ -0,0 +1,3343 @@ +// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// Limitations: +// Leavescan will attempt to avoid comments, strings and char literals which it +// finds within the code. It is also capable of recognising escaped quotes, +// but complex combinations of escaping e.g. "\\\"\"\'" may fool the parser and +// result in false positives, or cause parsing to terminate prematurely (resulting +// in possible unreported problems. +// Leavescan can only parse what it sees, and is therefore oblivious to any +// non-trivial attempt to call a leaving function (i.e. by function pointer) +// Macros can also fool the parser (as is), but leavscan will now indicate +// whether the leaving invocation may, in fact, be a macro. +// Multiple files are now supported on the command-line, along with some basic +// options such as '-v' which will dump the version. Invoking with no +// parameters will dump the version & help, so that automated build systems can +// check the version and cater for enhanced behaviour. +// Local Version: +// $Id: leavescan2.cpp,v 1.6 2003/02/19 12:59:00 AndrewHa Exp $ +// +// + + +#include +#include +#include +#include +#include +#include + +#define FOREVER for(;;) + +//static const char Kversion[] = "0.06"; // Version updated 07 March 08 +static const char Kversion[] = "0.07"; // suprrot L class, fix some defects.Version updated 07/2008 +// Shorthand +typedef unsigned int uint; + +// Set of match types. E_Last must be at the end of the list. +enum TMatchTypes { + E_LCleanedUp=0, + E_LString, + E_LManaged, + E_LData, + E_Ell , + E_Trap, + E_BlockComment, + E_LineComment, + E_Eleave, + E_UserEleave, + E_String, + E_Quote, + E_OpenBrace, + E_CloseBrace, + E_OrLeave, + E_Last }; + +// Set of return values of GetFunc(). +enum TReturnTypes { + E_False = 0, + E_True, + E_Continue }; + +enum TPPState { + PPSTATE_NORMAL=0, + PPSTATE_ESCAPED_LINE , + PPSTATE_SINGLE_COMMENT, + PPSTATE_MUL_COMMENT, + PPSTATE_STRING_LITERAL, + PPSTATE_SHARP_COMMENT + }; + +enum TClassMemberTypes { + E_NA= 0, + E_MemberData, + E_MemberFunctionDecl, + E_MemberFunctionDef, + E_Enum + }; + +using namespace std; +struct ClassMeta { + string className ; + int startPos; + int endPos; +}; + +class TLeaveScanModel +{ +public: + bool Scan(ifstream& aStream); + void SetFileName(char* aName); + char* FileName(); + int Verbose; + bool OnlyPrePrecess; + +private: + void FileToText(ifstream& aStream, string& aText); + enum TReturnTypes GetFunc(const string& aFile, string &name, uint &start, uint &end); + bool CheckFunc(const string& aFile, string& aName, uint start, uint end, bool& aIsLeaver); + bool MoveToEndOfTrapHarness(const string& aStr, uint& aIndex, uint aLen); + void MoveToEndOfComment(const string& aStr, uint& aIndex, uint aLen); + void MoveToEndOfLine(const string& aStr, uint& aIndex, uint aLen); + void MoveToEndOfString(const string& aStr, uint& aIndex, uint aLen, char aQuote); + uint GetRealStartPosition(const string& aFile, uint aStart, uint aIsvalidDoublecolon); + void Peek(const string aStr, uint aPos); + uint SmartFind(const string& aStr, const string& aTarget, uint aStart); + uint SmartFindEndOfString(const string& aStr, uint aPos, char aQuote); + bool IsInCommentScopeOrKeyword(const string& aFile, string &aName, uint aStartposition, uint aStartbraceposn); + bool IsFunctionNameStringNotAMacro(const string& aFile, uint aStartbraceposn, uint aTempParenPos, uint aNstart); + bool IsSemiColonAndAssignmentOccurs(const string& aFile, uint aStartbraceposn, uint aTempParenPos); + bool CheckValidFuncName(const string& aFile, uint aStart); + bool CheckForTemplateFunc(const string& aFile, uint nstart, uint nend); + uint FindFirstMatchType(uint aMatchSet[]); + string PreProcess(const string& aFile); + string CombineLine(const string& aFile); + list GetClass(const string& aFile); + int GetLeftParenthesis(const string& aText, uint pos); + int GetRightParenthesis(const string& aText, uint pos); + int GetLeftTmpltParentBack(const string& aText,uint pos); + int GetRightTmpltParent(const string& aText,uint pos); + bool IsClassKeyword(const string& aText, uint aBegin, uint aEnd); + int GetLeftBracket(const string& aText,uint pos); + int GetRightBracket(const string& aText,uint pos); + void CheckClass(const string& aText , const string& aClassName, uint start,uint end); + void CheckInClassFunc(const string& aText , const string& aClassName, const string& aFuncName, uint start,uint end); + bool IsLClassCtor(const string& aName); + bool IsInClassScope(uint pos); + string GetFunctNameFromFuncHead(const string& aFuncHead); + string GetFunctionParam(const string& aText, uint aStart); + string GetFunctionHead(const string& aText, uint aStart); + string GetErrorLineHead(const string& aText,uint aStart); + string GetClassName(uint aStart); + void ReportErrorLineAndString(uint aStart); + bool AppendCommentToErrorString(uint aEnd); + bool IdentifyMacro(const string& str, const uint aPos); + void Test1(); + void Test2L(); + void Test3(); + void Test4(); + + inline bool IsNewLine(const char& aCurChar) {return ((aCurChar)=='\n'||(aCurChar)=='\r')?true:false;} + inline bool IsLastChar(uint aCurPos, uint aStringLength) { return ((aCurPos+1)==aStringLength)?true:false;} + inline bool HasEnoughChar(uint aCurPos,uint aStringLength,uint aWanted) {return (aStringLength-aCurPos-1>=aWanted)?true:false;} + inline string TrimString(const string& aStr) + { + string result = aStr; + result.erase(result.find_last_not_of(" \t\n\r")+1); + result.erase(0,result.find_first_not_of(" \t\n\r")); + return result; + } +private: + string iText; + string iBody; + string iErrorString; + list iClassList; + int iPositionOfError; + char* iFileName; + +}; + +void pversion() +{ + cout << "Leavescan version: " << Kversion <<"(build time:"<<__DATE__<<" "<<__TIME__<<")\n"; +} + +void pusage() +{ + pversion(); + cout << "syntax: \n\tleavescan [-h|-n|-v|-N] [ ...]\n\n"; + cout << "\t-h: This help.\n"; + cout << "\t-n: Noisy output - provides diagnostics (if available).\n"; + cout << "\t-N: Very noisy output - provides diagnostics (if available).\n"; + cout << "\t-v: Displays version (for build & automation systems).\n"; + cout << "\t-E: Only do pre-process\n\n"; + +} + +int main(int argc, char** argv) +{ + int noisy = 0; + bool onlyPreProcess =false; + if (argc < 2) + { + pusage(); + return 1; + } + + for (int clparam = 1; clparam < argc; clparam++) + { + if (argv[clparam][0] == '-') + { + switch(argv[clparam][1]) + { + case 'n': + noisy = 1; + break; + case 'N': + noisy = 2; + break; + case 'h': + pusage(); + break; + case 'v': + pversion(); + break; + case 'E': + { + onlyPreProcess = true; + } + break; + default: + pusage(); + break; + } + } //if + else + { + // invoked once per file + TLeaveScanModel model; + model.SetFileName(argv[clparam]); + model.Verbose = noisy; + if(onlyPreProcess) + { + model.OnlyPrePrecess = true; + } + else + { + model.OnlyPrePrecess = false; + } + ifstream file(model.FileName()); + (void) model.Scan(file); + file.close(); + // return 0; + } + } + return 0; +} + +void TLeaveScanModel::SetFileName(char *aName) +{ + iFileName = aName; +} + +char* TLeaveScanModel::FileName() +{ + return iFileName; +} + +// +// Main processing function which converts the file to a basic::string +// and then searches through for methods, analysing them as they are +// located. +bool TLeaveScanModel::Scan(ifstream& aStream) +{ + FileToText(aStream, iText); + string oldText(iText); + iText = PreProcess(iText); + if(OnlyPrePrecess) + { + cout<::iterator iter; + for(iter=iClassList.begin();iter!=iClassList.end();iter++) + { + CheckClass(iText,iter->className,iter->startPos,iter->endPos); + } + return true; +} + +// +// Spool a file into one large basic::string +// +void TLeaveScanModel::FileToText(ifstream& aStream, string& aText) +{ + char data[1024]; + int len; + do + { + aStream.read(data,1024); + len = aStream.gcount(); + aText.append(data, len); + } + while(len); +} + +// To get the actual position of starting parenthesis for a function definition +// +uint TLeaveScanModel::GetRealStartPosition(const string& aFile,uint aStart, uint aIsvaliddoublecolon) +{ + uint realstartpos = 0; + + // The opening parenthesis which comes fist after opening brace while moving + // in backward direction is a valid candidate for function name. + + uint firstcurlybrace = SmartFind(aFile, "{", aStart + 1 ); // advance start + + if ((firstcurlybrace == string::npos) || (firstcurlybrace >= aFile.length())) + { + return realstartpos; + } + + // This variable will store the first paranthesis position + uint tempParenPos = aFile.find_last_of('(',firstcurlybrace); + + if (tempParenPos == string::npos) + { + // No '(' found yet + return realstartpos; + } + + if (aIsvaliddoublecolon == 1) + { + tempParenPos = aStart; + } + + string whiteSpaceChars = " \t\n\r*&"; + + // ignore all tab and spaces between function name and opening parenthesis + uint nend = aFile.find_last_not_of(whiteSpaceChars, --tempParenPos); + uint pos = aFile.find_last_of(whiteSpaceChars, nend); + + if (pos == string::npos) + { + return realstartpos; + } + else + { + return pos; + } +} +/* +This function checks the following : +1) Whether the name is in comment scope, name is checked for both C-style comments(or block comments) and C++-style comments(Line Comments) +2) The function name is not a keyword having same program construct as function name(i.e. is not among 'while', 'for','if' and 'for' + +@internalComponent +@released +@param aFile - Buffer storing the whole source file contents(input) +@param aName - String that is to be checked whether it lies in the scope of the comment(input) +@param aStartposition - Starting offset of name in file.(input) +@param aStartbraceposn - Starting offset of function block (input) +@param true - if name is in comment scope(output) +@param false - if name is not in comment scope + + +Following patterns are handled in this function: +----------------------------------------------- +NOTE: in order to remove compile warning, i use "|" stand for "/" in this section of comment + +Pattern 1: String is in the scope of both c-style and C++-style comments + + |* + || name1 + * | + + +Pattern 2: String is in the scope of both c-style comments + + |* + name2() + * | + +Pattern 3: String is in comment scope and the comment scope llies in a string + + printf(" |* * | || ") + + +Pattern 4: String is in the scope of C++-style comments but C-style comments is also available in souurce file + + |* + + * | + + || function() + + + +Pattern 5: String is in the scope of C-style comments but C+++-style comments is also available in souurce file + + || function() + |* + + * | + + +Pattern 6: The string is a keyword and the program construct for the keyword is same as for the functions + for() + { } + + +Pattern 7: Both C-style and C++-style comments are avialable in file and the way of specifying comments + is complex.(i.e. it is difficult to identify whether it is a C-Style comment or C++-style comment + ||******* + fun() + |****** + **** | + {} + +*/ +bool TLeaveScanModel::IsInCommentScopeOrKeyword(const string& aFile, string &aName, uint aStartposition,uint aStartbraceposn) +{ + uint blockCommentStartPosn = aFile.rfind("/*",aStartposition); // In backward direction + uint lineCommentStartPosn = aFile.rfind("//",aStartposition); + uint blockCommentEndPosn = aFile.find("*/", aStartposition); // In forward direction + uint semicolon = aFile.rfind(";",aStartposition); + uint isvalidlocationforBlock; + uint isvalidlocationforLine ; + + if( (0 == strcmp(aName.c_str(),"if")) || (0 == strcmp(aName.c_str(),"while")) || + (0 == strcmp(aName.c_str(),"for"))|| (0 == strcmp(aName.c_str(),"switch")) || + (0 == strcmp(aName.c_str(),"defined"))) + { + return true; + } + // There is no comment of any type either block comment or line comment + if(blockCommentStartPosn == string::npos && lineCommentStartPosn == string::npos) + { + return false; + } + // A semiclon exists and semicolon is followed by both (1) the end of block comment scope and (2) the end of line comment scope + else if((semicolon != string::npos)&& + ((semicolon > blockCommentEndPosn) && (blockCommentStartPosn < blockCommentEndPosn)) && + (semicolon > lineCommentStartPosn)) + { + return false; + } + else if(lineCommentStartPosn == string::npos) + { + // Valid Block comment, verify that the function name by applying smartfind + isvalidlocationforBlock = SmartFind(aFile, aName, blockCommentStartPosn); + if( (isvalidlocationforBlock == string::npos) || // There is no occurrence of name + ((isvalidlocationforBlock > aStartbraceposn) && (isvalidlocationforBlock != string::npos))) // The name exists but that is inside function block + { + return true; + } + else + { + return false; + } + } + else if(blockCommentStartPosn == string::npos) + { + isvalidlocationforLine = SmartFind(aFile,aName, lineCommentStartPosn); + if( (isvalidlocationforLine == string::npos) || // There is no occurrence of name + ((isvalidlocationforLine > aStartbraceposn) && (isvalidlocationforLine != string::npos) ) ) // The name exists but that is inside function block + { + return true; + } + else + { + return false; + } + } + else + { + isvalidlocationforBlock = SmartFind(aFile,aName, blockCommentStartPosn); + isvalidlocationforLine = SmartFind(aFile,aName, lineCommentStartPosn); + if((isvalidlocationforLine == string::npos) ) + { + return true; + } + else if(( (isvalidlocationforLine > aStartbraceposn) && (isvalidlocationforLine != string::npos)) ) + { + return true; + } + else if( (0 == isvalidlocationforBlock) || ((isvalidlocationforBlock > aStartbraceposn) && (isvalidlocationforBlock != string::npos)) ) + { + return true; + } + else if(( blockCommentStartPosn < aStartbraceposn) && (blockCommentEndPosn < aStartbraceposn ) && (blockCommentStartPosn < blockCommentEndPosn) && ((isvalidlocationforBlock == string::npos))) + { + return true; + } + else + { + return false; + } + } +} + +/* +This function checks whether the function name is a macro or not + +@internalComponent +@released +@param aFile - Buffer storing the whole source file contents +@param aStartbraceposn - Starting offset of function block (input) +@param aParenPos - End position of function signature +@param aStartposnofname - Starting offset of string that is to be considered as a function name +@param true - If function name is not a macro +@param false - If function name is a macro + +Following patterns are handled in this function: +----------------------------------------------- + +Pattern 1: Function is invoked in macro + + #if defined macro() + #endif + struct s1 + { + + } + +Pattern 2: Function is invoked in macro but the macro itself is in comment scope + void fun() + // #if macro() + // #endif + { + struct s1 + { + + } + } + +Pattern 3: There is parameterized Constructor e.g. + + Foobar(CFileMan* aFileMan) : iFileMan(aFileMan), iCurrentStep(0) {} + + +Pattern 4: Function is defined on the preprocessor statement e.g + + #define __KTRACE_ALL(a,p) {if((DEBUGMASK&(a))==(a))p;} + +Pattern 5: All the functions name in comment scope will be ignored + + void func() + // #if comments() + { + + } + +Pattern 6: All the functions name (e.g. comments) in comment scope will be ignored + + #if defined() + // comments() + struct{ + } + +*/ + +bool TLeaveScanModel::IsFunctionNameStringNotAMacro(const string& aFile, uint aStartbraceposn, uint aParenPos, uint aStartposnofname) +{ + uint startofword = 0; + uint endofword = 0; + uint tempParenPos = 0; + bool posn = true; + string whiteSpaceChars = " \t\n\r"; + uint tempColonPosn = SmartFind(aFile,":",aParenPos); + string colonString(":"); + bool isColonInCommentScope = IsInCommentScopeOrKeyword(aFile,colonString,aParenPos,aStartbraceposn); + if( (tempColonPosn != string::npos) && + (false == isColonInCommentScope) && + (tempColonPosn < aStartbraceposn) ) + { + return true; // Not a macro + } + // The function ignores all the strings which are in the scope of block comments. + while( startofword < aStartbraceposn && endofword < aStartbraceposn && posn == true) + { + if(tempParenPos == 0) + { + tempParenPos = aParenPos; // First word + } + else + { + tempParenPos = endofword; // Next word + } + startofword = aFile.find_first_not_of(whiteSpaceChars, tempParenPos+1); + if(startofword != aStartbraceposn) // No string between function signature and function start block + { + // get the posn of word end boundary + endofword = aFile.find_first_of(whiteSpaceChars, startofword); + string tmpString = aFile.substr(startofword,endofword-startofword); + string &aName = tmpString; + //is throw? + if(0==aName.find("throw")) + { + return true; + } + if( (0 == strcmp(aName.c_str(),"const")) || + (0 == strncmp(aName.c_str(),"//",2)) || + (0 == strncmp(aName.c_str(),"*/",2)) || + (0 == strncmp(aName.c_str(),"/*",2)) ) + { + // do nothing + } + else + { + // If string is in comment scope then it is fine i.e. the function returns true; + posn = IsInCommentScopeOrKeyword(aFile,aName,startofword,aStartbraceposn); + } + } + else + { + // Pattern 1: only spaces are there between ')' and '{' e.g. void fun() {} + posn = true; + } + } + if(posn == false) + { + return false; + } + uint endOfLine=aFile.rfind('\n',aStartposnofname); // Get the new line position while backtracking + uint aIndex=(endOfLine==string::npos ? 0 : endOfLine); + uint preprocessorDirective = aFile.rfind("#",aStartposnofname); // Get the first char of the line starting with # + if(preprocessorDirective != string::npos && aIndex <= preprocessorDirective) + { + return false; // // Yes, the first char is #, so the name on this line can not be a valid function name + } + // Check whether it is a macro + return true; +} + + + +/* +This function checks whether any semocolon (';') or assignment(=) is encountered +when the backtracking is done to look for function name. + +@internalComponent +@released +@param aFile - Buffer storing the whole source file contents +@param aStartbraceposn - Starting offset of function block (input) +@param aTempParenPos - End position of function signature +@param true - if either assignment expression '=' or ':' occurs between function signature and starting curly brace of function block. +@param false - if neither assignment expression '=' nor ':' occurs between function signature and starting curly brace of function block. + + +Following patterns are handled in this function: +----------------------------------------------- + +Pattern 1: The semicolon is encountered while backtracking in the search of function name + + _LT(); + struct s1 + { + + } + +Pattern 2: The semicolon is encountered while backtracking in the search of function name + + fun(); + a = 2; + struct str1 + { + + } + +Pattern 3: The assignment is encountered while backtracking in the search of function name + + voidmain() + a[2] = + { + 1,2,3 + } + +*/ + +bool TLeaveScanModel::IsSemiColonAndAssignmentOccurs(const string& aFile,uint aStartbraceposn ,uint aTempParenPos) +{ + string semicolon(";"); + string assignment("="); + uint tempSemicolonPosn = SmartFind(aFile,semicolon,aTempParenPos-1); + //uint tempAssignMentPosn = SmartFind(aFile,assignment,aTempParenPos-1); + bool isSemicolonInCommentScope = IsInCommentScopeOrKeyword(aFile,semicolon,aTempParenPos,aStartbraceposn); + bool isAssignmentInCommentScope = IsInCommentScopeOrKeyword(aFile,assignment,aTempParenPos,aStartbraceposn); + if( (tempSemicolonPosn != string::npos) && + ((false == isSemicolonInCommentScope) || (false == isAssignmentInCommentScope)) && + (tempSemicolonPosn < aStartbraceposn) + ) + { + return false; + } + return true; +} + +/* +This function checks whether the function definition is terminated by semi colon + +If the function definition is terminated with semicolon, then it is +more likely to be a class/struct declaration rather than a function definition. + +@internalComponent +@released +@param aFile - Buffer storing the whole source file contents +@param aStart - Starting offset of the function name string +@return true - If closing brace corresponding to function names is followed by semicolon +@return false - If closing brace corresponding to function names is not by semicolon + +Following patterns are handled in this function: +----------------------------------------------- + +Pattern 1: NONSHARABLE_CLASS/NONSHARABLE_STRUCT modifier is used + + NONSHARABLE_CLASS(...) + { + + }; + +Pattern 2: function definition is terminated by semicolon + + aaa(...) + { + + } // comment + ; + +Pattern 3: Class is defined in macro + + #define MACRO(arg) class name { }; + +*/ + +bool TLeaveScanModel::CheckValidFuncName(const string &aFile, uint aStart) +{ + bool returnValue=false; + unsigned long uiNumberOfCurlyBraces = 1; + unsigned int TempPosn = aStart; + unsigned int open_brace = 0; + unsigned int close_brace = 0; + // Continue till than at least any of open curly or close curly brace is remaining + while( !(open_brace == string::npos) || !(close_brace == string::npos) ) + { + open_brace = SmartFind(aFile, "{", TempPosn+1); + close_brace = SmartFind(aFile, "}", TempPosn+1); + + if(open_brace < close_brace) // Handle which curly comes first + { + if((open_brace != string::npos)&& open_brace < aFile.size()) + { + uiNumberOfCurlyBraces++; // Update the curly counter + TempPosn = open_brace; // move forward to the value from where the search of next curly to be started + } + } + else // close brace comes first + { + if((close_brace != string::npos)&& close_brace < aFile.size()) + { + uiNumberOfCurlyBraces--; + TempPosn = close_brace; // move forward to the value from where the search of next curly to be started + } + if(uiNumberOfCurlyBraces == 0) // Match to the corresponding close curly + { + break; + } + } + } + if(0 == uiNumberOfCurlyBraces) + { + string whiteSpaceChars = " \t\n\r"; + unsigned int braceFollowsSemicolon1 = 0; + unsigned int braceFollowsSemicolon2 = 0; + + braceFollowsSemicolon1 = SmartFind(aFile, ";", close_brace); // check if any semocolon exists after } + braceFollowsSemicolon2 = aFile.find_first_not_of(whiteSpaceChars,close_brace+1); // Get the next character after close_brace + + if( (braceFollowsSemicolon1 == braceFollowsSemicolon2) && (braceFollowsSemicolon1 != string::npos) && (braceFollowsSemicolon2 != string::npos)) + { + returnValue = true; + } + } + + return returnValue; +} +/* +This function checks whether the function name is specified with template class definition + +@internalComponent +@released +@param nstart - starting offset of the function name string +@param nend - end offset of the function name string +@return true - If function name is specified with template class functtion definition +@return false - If function name is not specified with template class functtion definition + +Following patterns are handled in this function: +----------------------------------------------- + +Pattern 1: + + +template +GLDEF_C void TestTDes::Test1() +{ + T a(_TL("ABc")); +} +*/ + +bool TLeaveScanModel::CheckForTemplateFunc(const string& aFile,uint nstart,uint nend) +{ + bool returnValue = false; + uint OpennAnglebracket = aFile.find_first_of("<", nstart); // advance start + if(nend == OpennAnglebracket ) // The first invalid char name is < + { + uint OpennParen = aFile.find_first_of("(", nstart); // advance start + uint CloseAnglebracket = SmartFind(aFile, ">::", nstart ); + if( (CloseAnglebracket < OpennParen) && (CloseAnglebracket > OpennAnglebracket)) + { + returnValue = true; + } + } + return returnValue; +} + +// Seek out mathod functions and return their name and start/end bounds in the +// string file. +// +enum TReturnTypes TLeaveScanModel::GetFunc(const string& aFile, string &aName, uint &start, uint &end) +{ + uint nstart = 0;//, cstart = 0; + uint initStart = start; + int realnstart = string::npos; + uint safety = 1000000; + string validNameChars = ":~abcdefghilkjmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890"; + uint prevstart = string::npos; + FOREVER// do // forever + { + if( + (start == string::npos) || + (prevstart == start && prevstart != string::npos) + ) + { + return E_False; + } + prevstart = start; + + if (safety-- == 0) + { + cout << "ERROR: GetFunc context failure in " << iFileName << "\n"; + exit(6); + } + + // move start along to 'real' double-colon + uint startColon = SmartFind(aFile, "::", start); + uint parenPostn = SmartFind(aFile, "(", start + 1); + + if (startColon == string::npos || startColon >= aFile.length() ) + { + // Function Definition do not have any :: and function body contains + nstart = start; + // For 1st function, the value of start will be zero and for the + // second function onwards, it will start after the first function ends + } + else + { + uint Realstartpost = GetRealStartPosition(aFile,parenPostn,0); + // If no real function name exists after double colon + // if (Realstartpost == 0) + // return E_False; + uint Realstartopnparen = SmartFind(aFile, "(", Realstartpost + 1); + + if(startColon < Realstartopnparen) + { + // If the double colon is used for function name then get function name which exists after :: + nstart = startColon; + //Get funcName before :: for "La :: La" + //step1 ':: L...' + uint fileLen = aFile.length(); + int tmpnstart=nstart+2; + bool step1 = false; + while (tmpnstart)? :: L... -->skip all the blank + bool step2 = true; + tmpnstart = nstart-1; + while (tmpnstart>=0) + { + char curChar = aFile[tmpnstart]; + if (curChar==' ' || curChar =='\n' || curChar=='\r' ||curChar=='\t') + { + tmpnstart--; + } + else + { + break; + } + } + if(tmpnstart<=0) + { + tmpnstart = 0; + step2 = false; + } + else + { + char curChar = aFile[tmpnstart]; + if (curChar=='>') + { + tmpnstart = GetLeftTmpltParentBack(aFile,tmpnstart-1); + if(tmpnstart==string::npos) + { + //bad pattern + step2 =false; + } + else + { + tmpnstart --; + } + } + if(tmpnstart==string::npos) + { + //bad pattern + step2 =false; + } + else + { + + while (tmpnstart>=0) + { + curChar = aFile[tmpnstart]; + if (curChar==' ' || curChar =='\n' || curChar=='\r' ||curChar=='\t') + { + tmpnstart--; + } + else + { + break; + } + } + if(tmpnstart <=0) + { + tmpnstart=0; + step2=false; + } + while (tmpnstart>=0) + { + curChar = aFile[tmpnstart]; + if (curChar=='_' || (curChar>='a' && curChar<='z') || (curChar>='A' && curChar<='Z') ||(curChar>='0' && curChar<='9')) + { + tmpnstart--; + } + else + { + break; + } + } + tmpnstart++; + if (tmpnstart<0) + { + tmpnstart=0; + step2=false; + } + if ( step2 && aFile[tmpnstart]=='L') + { + realnstart = tmpnstart; + } + } + + } + } + } + else + { + // start looking for function name after '(' + nstart = aFile.find_last_of(validNameChars,parenPostn-1); + if(nstart == string::npos) + return E_False; + } + } + + uint semiPos = SmartFind(aFile, ";", nstart + 1); + + if (semiPos == string::npos || semiPos >= aFile.length()) + return E_False; + + uint parenPos = SmartFind(aFile, "(", nstart + 1); + if (parenPos == string::npos || parenPos >= aFile.length()) + return E_False; + + start = SmartFind(aFile, "{", nstart + 1); // advance start + if (start == string::npos || start >= aFile.length()) + return E_False; + + uint nstart2 = SmartFind(aFile, "::", nstart + 1); // next fn + // Either (1) Second instance of Double collon is not there and first occurrence of double colon is valid + // or (2) second occurrence of double colon is inside the function and first occurrence of double colon is valid + + if((nstart2 == string::npos && startColon < parenPos && startColon < start) || ( nstart2 > start && startColon < parenPos && startColon < start )) + { + // This variable will store the first paranthesis position in a temporary variable + // uint TempparenPos = parenPos; + uint Realstartpost = GetRealStartPosition(aFile,parenPos,1 /*To indicate that a valid double colon exists*/); + + nstart = Realstartpost+1; // reset + + break; + } + // Either Second occurrence of Double-colon is invalid + // or Second occurrence of Double-colon exists inside the function + // while first occurrence of double colon is valid + else if (nstart2 == string::npos || nstart2 >= aFile.length() || (nstart2 != string::npos && nstart2 > start && startColon < parenPos && startColon < start)) + { + // The opening parenthesis which comes fist after opening brace while moving + // in backward direction is a valid candidate for function name. + + // This variable will store the first paranthesis position + uint tempParenPos = aFile.find_last_of('(',start); + + + //void foo() throw () {;} + if(tempParenPos != string::npos) + { + uint throwPos = aFile.find("throw",initStart); + if(throwPos!=string::npos && throwPos>=initStart && throwPosparenPos) + { + int tmpRightBracket = GetRightBracket(aFile,semiPos); + if(tmpRightBracket!=string::npos) + { + start = tmpRightBracket; + return E_Continue; + } + } + + // No '(' found yet + return E_False; + } + + + string whiteSpaceChars = " \t\n\r*&"; + + // ignore all tab and spaces and pointer between function name and opening parenthesis + uint nend = aFile.find_last_not_of(whiteSpaceChars, --tempParenPos); + uint currPos = aFile.find_last_of(whiteSpaceChars, nend); + + uint startOfBlock = SmartFind(aFile, "{", tempParenPos ); // advance start + + if (startOfBlock == string::npos || startOfBlock >= aFile.length()) + return E_False; + + if (start < tempParenPos || nstart2 < tempParenPos) + { + start = startOfBlock; + } + + if ((currPos != string::npos) && (currPos < tempParenPos)) // fn1 before fn2 + nstart = currPos+1; // reset + break; + } + + if (semiPos < start) // semi came before brace = prototype + start = semiPos; + else + if (nstart < nstart2 // fn1 before fn2 + && nstart2 < parenPos) // fn2 before paren + start = nstart2; // reset + else + break; + } //while (true); + + // nstart should be left pointing to first of double colons + // start should point to curly brace + + assert(aFile[start] == '{'); + + // locate the end of the method name + nstart = aFile.find_first_of(validNameChars,nstart); + if(nstart == string::npos) + return E_False; + + int nend = aFile.find_first_not_of(validNameChars, nstart); + if(true == CheckForTemplateFunc(aFile,nstart,nend)) + { + nend = aFile.find_first_of("(",nstart); + } + + if(realnstart!=string::npos && realnstart=0) + { + char tmpChar = aFile[nend]; + if(tmpChar == ' ' || tmpChar == '\n' ||tmpChar == '\t' ||tmpChar == 'r') + { + nend--; + } + else + { + break; + } + } + aName = aFile.substr(nstart, nend - nstart); + } +int typeEnd = aFile.find_last_of(validNameChars,nstart-1); +int typeStart= aFile.find_last_of(" \t\n\r*&",typeEnd)+1; +string type=TrimString(aFile.substr(typeStart, typeEnd - typeStart+1)); + uint closeparenposn = aFile.find_first_of(")", nstart); // advance start + + if( + (false == IsFunctionNameStringNotAMacro(aFile,start,closeparenposn,nstart)) || + (false == IsSemiColonAndAssignmentOccurs(aFile,start,closeparenposn)) + ) + { + + start = SmartFind(aFile, "}", start); + return E_Continue; + } + + // rewind nstart until non valid char found + safety = 1000000; + while (validNameChars.find_first_of(aFile[--nstart]) != string::npos) + { + if (safety-- == 0) + { + cout << "ERROR: GetFunc context failure in " << iFileName << "\n"; + exit(7); + } + } + + nstart++; // skip forward to acceptable character + + // cut name out + if(realnstart!=string::npos && realnstart 0) + { + if (Verbose > 1) + cout << "."; + + // reset all types (in case we don't use all of them) + int counter; + for (counter = E_LCleanedUp; counter < E_Last; counter++) + match[counter] = string::npos; + + match[E_OpenBrace] = aFile.find("{", lpos); + match[E_CloseBrace] = aFile.find("}", lpos); + match[E_BlockComment] = aFile.find("/*", lpos); + match[E_LineComment] = aFile.find("//", lpos); + match[E_String] = aFile.find("\"", lpos); + match[E_Quote] = aFile.find("\'", lpos); + + // Check for at least one match-type + bool nothingFound = true; + for(counter = E_LCleanedUp; counter < E_Last; counter++) + { + if(match[counter] != string::npos) // if found an item + nothingFound = false; + } + + if(nothingFound) + { + if (Verbose > 1) + cout << "\n"; + cout << "ERROR: " << iFileName << ":" << aName << " failed brace check.\n"; + exit(1); + } + + // Find the match-type which occurs first and set + // lps to its position + uint lowestMatchType = FindFirstMatchType(match); + lpos = match[lowestMatchType]; + + switch(lowestMatchType) + { + case E_BlockComment: + MoveToEndOfComment(aFile, lpos, string::npos); // lpos modified + break; + + case E_LineComment: + MoveToEndOfLine(aFile, lpos, string::npos); // lpos modified + break; + + case E_OpenBrace: + braceCount++; + if (braceCount > (int)braceDepth) + braceDepth = braceCount; + lpos++; + break; + + case E_CloseBrace: + braceCount--; + lpos++; + break; + + case E_String: + // we're sat on a quote, so advance + lpos++; + // Peek(file,lpos); + lpos = SmartFindEndOfString(aFile, lpos, '\"'); + if (lpos != string::npos) + lpos++; // skip closing quote + break; + + case E_Quote: + lpos++; + lpos = SmartFindEndOfString(aFile, lpos, '\''); + if (lpos != string::npos) + lpos++; // skip closing quote + break; + + default: + if (Verbose > 1) + cout << "\n"; + cout << "ERROR: " << iFileName << ":" << aName << " bad match type.\n"; + exit(1); + } //endsw + + if (lpos == string::npos || lpos == 0 || lpos > aFile.length()) + { + if (Verbose > 1) + cout << "\n"; + cout << "ERROR: " << iFileName << ":" << aName << " failed brace check (EOF).\n"; + exit(1); + } + + } //endwhile + + // advance 'end' + end = lpos; + + if (braceDepth > 10) + { + if (Verbose > 1) + cout << "\n"; + cout << "WARNING: " << iFileName << ":" << aName << " unexpectedly large brace depth.\n"; + } + return E_True; +} + +// Diagnostic function for displaying the contents of a string +// starting at 'pos' +// +void TLeaveScanModel::Peek(const string aStr, uint aPos) +{ +#define PEEKBUFFSIZE 20 + static char peekBuf[PEEKBUFFSIZE]; + int posn = aPos; + int remaining = aStr.length() - posn; + + if (remaining > (PEEKBUFFSIZE - 1)) + remaining = PEEKBUFFSIZE; + + for (int i = 0; i < remaining; i++) + peekBuf[i] = aStr[i+posn]; + + peekBuf[remaining] = 0; + + cout << "-------- Peek -----------\n" << peekBuf << "\n"; + cout << "-------------------------\n"; +#undef PEEKBUFFSIZE +} + +// Given an array of match types, work out which one actually comes first +// in the string. Effectively this function returns the match type with the +// lowest 'pos' value. +// +uint TLeaveScanModel::FindFirstMatchType(uint aMatchSet[]) +{ + // load indexOfLowestMatch with the item which comes first in the fn + int lowestMatch = 0; + for(int i = E_LCleanedUp; i < E_Last; i++) + { + if((aMatchSet[lowestMatch] == string::npos) // if didn't find one + ||(aMatchSet[lowestMatch] > aMatchSet[i] && aMatchSet[i] != string::npos)) + lowestMatch = i; + } + // cout << "Lowest match found: " << (int)lowestMatch << "\n"; + return lowestMatch; +} + +// +// Given a string, see if it looks like a macro (e.g. is capitalised) +// +bool TLeaveScanModel::IdentifyMacro(const string& str, const uint aPos) +{ + string validNameChars = ":~abcdefghilkjmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890"; + string LowerNameChars = "abcdefghilkjmnopqrstuvwxyz"; + + // backwind until not valid + int start = str.find_last_not_of(validNameChars, aPos); + + // check for any lower case between start and pos + int lower = str.find_first_of(LowerNameChars, start); + + bool result = false; + if (lower < (int)aPos) + result = false; // lower case == not macro + else + result = true; + return result; +} + +// Given a method function bound, search thorough it looking for what appear to be +// leaving functions (unless it's a leaver itself). +// +// Returns false if error was detected signifying that caller should dump the +// error string. +// +bool TLeaveScanModel::CheckFunc(const string& aFile, string &aName, + uint start, uint end, bool& aIsLeaver) +{ + // entry criteria: name points to the container function name (after double-colon) which + // is now null-terminated. + // end is the bound for the end of the function (closing curly brace) + string extraTypes="CDX"; + // Look for container name ending in L, or LC, LD, or LX + bool isLCFunc =false; + aName = TrimString(aName); + + string className=""; + className = GetClassName( start); + if(className!="") + { + aName = className+"::"+aName; + } + + if (Verbose > 1) + { + cout << "Evaluating code:\n"; + Peek(aFile, start); + } + + if (aName[aName.length()-1] == 'L' || + (aName[aName.length()-2] == 'L' && string::npos != extraTypes.find(aName[aName.length()-1]) ) ) + //return true; // happy - we can exit since this container is marked as a leaver + aIsLeaver = true; // container is marked Leaver - used to return here + else if(IsLClassCtor(aName)) + { + aIsLeaver = true; + } + + else + aIsLeaver = false; // container not marked Leaver + + if (aName[aName.length()-1] == 'C' && aName[aName.length()-2] == 'L' ) + { + isLCFunc =true; + } + //CheckFuncDecl + //CheckFuncParam + int classNamePos = aFile.rfind(aName, start); + if(classNamePos == string::npos) + { + uint coloncolonPos = aName.find("::"); + if(coloncolonPos != string::npos) + { + string shortFuncName = aName.substr(coloncolonPos+2); + classNamePos = aFile.rfind(shortFuncName,start); + } + } + string funcParam = GetFunctionParam(aFile, classNamePos-1); + if(funcParam != "") + { + if(funcParam.find("LString")!=string::npos||(funcParam.find("LData")!=string::npos)) + { + if(!aIsLeaver) + { + cout< 1) + cout << "?"; + // Scans for a whole set of items from position lpos. + // string::npos returned if not found + + // reset all types (in case we don't use all of them) + int counter; + for (counter = E_LCleanedUp; counter < E_Last; counter++) + match[counter] = string::npos; + + match[E_Ell] = iBody.find("L", lpos); + match[E_Trap] = iBody.find("TRAP", lpos); + match[E_BlockComment] = iBody.find("/*", lpos); + match[E_LineComment] = iBody.find("//", lpos); + match[E_Eleave] = iBody.find("ELeave", lpos); + match[E_UserEleave] = iBody.find("User::Leave", lpos); + match[E_String] = iBody.find("\"", lpos); + match[E_Quote] = iBody.find("\'", lpos); + match[E_OrLeave] = iBody.find("OR_LEAVE", lpos); + match[E_LCleanedUp] = iBody.find("LCleanedup", lpos); + match[E_LString] = iBody.find("LString", lpos); + match[E_LManaged] = iBody.find("LManaged", lpos); + match[E_LData] = iBody.find("LData", lpos); + + // Check for at least one match-type + bool doBreak = true; + for(counter = E_LCleanedUp; counter < E_Last; counter++) + { + if(match[counter] != string::npos) // if found an item + doBreak = false; + } + + if(doBreak) + break; // found nothing of interest in this method function + + // Find the match-type which occurs first and set + // lps to its position + uint lowestMatchType = FindFirstMatchType(match); + lpos = match[lowestMatchType]; + + switch(lowestMatchType) // what type was it? + { + case E_BlockComment: + MoveToEndOfComment(iBody, lpos, bodyLen); // lpos modified + break; + + case E_LineComment: + MoveToEndOfLine(iBody, lpos, bodyLen); // lpos modified + break; + + case E_Trap: + if (! MoveToEndOfTrapHarness(iBody, lpos, bodyLen)) // lpos modified + { + iErrorString = aName + " structure Fault-Unclosed bracket after TRAP harness."; + iPositionOfError = lpos; + keepProcessing = false; // bail + } + break; + + case E_Eleave: + ok = false; + iErrorString = aName + " calls new(ELeave)."; + iPositionOfError = match[E_Eleave]; + keepProcessing = false; // bail + break; + case E_OrLeave: + ok = false; + iErrorString = aName + " calls OR_LEAVE."; + iPositionOfError = match[E_OrLeave]; + keepProcessing = false; // bail + break; + case E_LCleanedUp: + ok = false; + iErrorString = aName + " uses LCleanedup* class."; + iPositionOfError = match[E_LCleanedUp]; + keepProcessing = false; // bail + break; + case E_LString: + ok = false; + iErrorString = aName + " uses LString* class."; + iPositionOfError = match[E_LString]; + keepProcessing = false; // bail + break; + case E_LManaged: + ok = false; + iErrorString = aName + " uses LManaged* class."; + iPositionOfError = match[E_LManaged]; + keepProcessing = false; // bail + break; + + case E_LData: + ok = false; + iErrorString = aName + " uses LData* class."; + iPositionOfError = match[E_LData]; + keepProcessing = false; // bail + break; + + case E_UserEleave: + ok = false; + iErrorString = aName + " calls User::Leave() or User::LeaveIfError()."; + iPositionOfError = match[E_UserEleave]; + AppendCommentToErrorString(bodyLen); + keepProcessing = false; // bail + break; + + + case E_Ell: + // Found an L, but is there an underbar before it, + // AND (one of 'CDX ' AND a brace OR just a brace) _L[CDX ]( + if ((iBody[lpos - 1] != '_') && + (((string::npos != extraTypesAndSpace.find(iBody[lpos + 1])) + && (iBody[lpos + 2] == '(')) || (iBody[lpos + 1] == '(')) ) + { + if (IdentifyMacro(iBody, lpos)) + { + ok = false; + iErrorString = aName + " may employ a macro."; + iPositionOfError = match[E_Ell]; + if(!AppendCommentToErrorString(bodyLen)) + keepProcessing = false; // keep going if possible + lpos++; + break; // don't bail - false alarm + } + else + { + if (Verbose > 1) + { + cout << "Leaver found: \n"; + Peek(iBody, lpos); + } + } + ok = false; + iErrorString = aName + " calls a function that can leave."; + iPositionOfError = match[E_Ell]; + if(!AppendCommentToErrorString(bodyLen)) + keepProcessing = false; // keep going if possible + } + lpos++; // move on over the L + break; + + case E_String: + lpos++; + lpos = SmartFindEndOfString(iBody, lpos, '\"'); + if (lpos == string::npos) + keepProcessing = false; + else + lpos++; // skip closing quote + break; + + case E_Quote: + lpos++; + lpos = SmartFindEndOfString(iBody, lpos, '\''); + if (lpos == string::npos) + keepProcessing = false; + else + lpos++; // skip closing quote + break; + + default: + cout << "\nERROR: " << iFileName << ": " << aName << " unexpected match type.\n"; + exit(1); + + } // endsw + //LCleanedup and LManaged cann't be TRAPed + /* + if (match[E_LCleanedUp]==string::npos && match[E_LManaged]==string::npos) + { + } + if(match[E_LCleanedUp]!=string::npos && match[E_LManaged]==string::npos) + { + ok = false; + iErrorString = aName + " uses LCleanedup class."; + iPositionOfError = match[E_LCleanedUp]; + keepProcessing = false; // bail + break; + } + else if(match[E_LManaged]!=string::npos && match[E_LCleanedUp]==string::npos) + { + ok = false; + iErrorString = aName + " uses LManaged* class."; + iPositionOfError = match[E_LManaged]; + keepProcessing = false; // bail + break; + } + else if(match[E_LCleanedUp]match[E_LManaged]) + { + ok = false; + iErrorString = aName + " uses LManaged* class."; + iPositionOfError = match[E_LManaged]; + keepProcessing = false; // bail + break; + } + */ + //check:An LCleanedup class is used in the same function body as the Classic cleanup stack API + if(match[E_LCleanedUp]!=string::npos) + { + uint newLCPos = iBody.find("NewLC"); + uint pushLPos = string::npos; //Cleanedup::PushL()-->find Cleanedup + uint bodyLen = iBody.length(); + for(uint tmpPos = 0;tmpPos0) + { + if(iBody[pushLPos-1]=='L') + { + tmpPos++; + pushLPos = string::npos; + continue; + } + else + { + break; + } + } + else + { + break; + } + } + + //uint new + uint lcleanedUpPos = match[E_LCleanedUp]; + if(newLCPos!=string::npos && pushLPos!=string::npos) + { + if(newLCPos 1) + cout << "END\n"; + + return ok; +} + +// +// Move an index forward to the start of a close-comment +// +void TLeaveScanModel::MoveToEndOfComment(const string& aStr, uint& aIndex, uint aLen) +{ + uint endOfComment=aStr.find("*/",aIndex); + aIndex=(endOfComment == string::npos ? aLen : endOfComment+2); +} + +// +// Move an index forward to the EOL (\n) +// +void TLeaveScanModel::MoveToEndOfLine(const string& aStr, uint& aIndex, uint aLen) +{ + uint endOfLine=aStr.find('\n',aIndex); + aIndex=(endOfLine==string::npos ? aLen : endOfLine); +} + +// +// Move an index forward to a closing quote (specified by x) +// +void TLeaveScanModel::MoveToEndOfString(const string& aStr, uint& aIndex, uint aLen, char aQuote) +{ + uint endOfLine=aStr.find(aQuote,aIndex); + aIndex=(endOfLine==string::npos ? aLen : endOfLine); +} + +// +// Move to end of a trap harness +// +bool TLeaveScanModel::MoveToEndOfTrapHarness(const string& aStr, uint& aIndex, uint aLen) +{ + uint bracketLevel=1; + uint closeBracket; + uint openBracket=aStr.find('(',aIndex); + bool cleanExit=true; + uint newIndex; + for(newIndex = openBracket; bracketLevel;) + { + closeBracket=aStr.find(')',newIndex+1); + openBracket=aStr.find('(',newIndex+1); + if (openBracket::iterator iter; + for(iter=iClassList.begin();iter!=iClassList.end();iter++) + { + if(iter->startPos<=aStart && iter->endPos >= aStart) + { + return iter->className; + } + } + return ""; +} +// +// Add to the current error string - note works on class member iBody +// +bool TLeaveScanModel::AppendCommentToErrorString(uint aEnd) +{ + bool qualified = true; + uint commentPosition = iBody.find("//",iPositionOfError+1); + uint endOfLinePosition = iBody.find('\n',iPositionOfError+1); + if((commentPosition < endOfLinePosition) && (commentPosition != string::npos)) + iErrorString+=" QUALIFIED WITH-> "+iBody.substr(commentPosition,endOfLinePosition-commentPosition); + else if(endOfLinePosition==string::npos && commentPosition!=string::npos) + iErrorString+=" QUALIFIED WITH-> "+iBody.substr(commentPosition,aEnd-commentPosition); + else //no comment + { + iErrorString+=" UnQualified."; + qualified = false; + } + return qualified; +} + +// +// Find the end of a string, but cope with escaped quotes +// +uint TLeaveScanModel::SmartFindEndOfString(const string& aStr, uint aPos, char aQuote) +{ + FOREVER//while(true) + { + MoveToEndOfString(aStr, aPos, string::npos, aQuote); + if (aPos == string::npos) // end of fn + return aPos; + + if (aStr[aPos - 1] != '\\') + return aPos; + + // looks like we have an escaped quote + if (aStr[aPos - 2] == '\\') + { // escape was itself quoted, so string end is real + return aPos; + } + else + { // quote is escaped - carry on + if (Verbose > 1) + cout << "\n"; + cout << "WARNING: " << iFileName << ": detected quoted string.\n"; + aPos++; + continue; + } + } //while +} + +// +// Find a target string from a given start position, but ignore targets buried +// within comments, or strings. +// +uint TLeaveScanModel::SmartFind(const string& aStr, const string& aTarget, uint aStart) +{ + uint found,cstart; + FOREVER//while(1) + { + // cout << "Searching for target from: " << aStart << "\n"; + // record found target + found = aStr.find(aTarget, aStart); + if (found == string::npos) + return(string::npos); + + // cout << "Target candidate found at: " << found << "\n"; + // look for earlier comment + cstart = aStr.find("//", aStart); + + if (cstart < found) // earlier + { + aStart = cstart; // reset start to after comment + // cout << "Earlier comment found at: " << start << "\n"; + MoveToEndOfLine(aStr, aStart, string::npos); + // cout << "Start advanced to: " << aStart << "\n"; + if (aStart == string::npos) + return(aStart); + else + continue; // start search again + } + + // do the same for block comments + cstart = aStr.find("/*", aStart); + if (cstart < found) + { + aStart = cstart; + // cout << "Earlier block found at: " << aStart << "\n"; + MoveToEndOfComment(aStr, aStart, string::npos); + // cout << "Start advanced to: " << aStart << "\n"; + if (aStart == string::npos) + return(aStart); + else + continue; + } + + cstart = aStr.find("\"", aStart); + + if (cstart < found) + { + aStart = cstart + 1; + MoveToEndOfString(aStr, aStart, string::npos, '\"'); + if (aStart == string::npos) + return(aStart); + else + { + aStart++; + continue; + } + } + + cstart = aStr.find("\'", aStart); + if (cstart < found) + { + aStart = cstart + 1; + MoveToEndOfString(aStr, aStart, string::npos, '\''); + if (aStart == string::npos) + return(aStart); + else + { + aStart++; + continue; + } + } + return(found); // quit loop + } // endwhile +} + + +/* + * Decide the "class" is keyword + * e.g + * class -> true + * Aclass ->false + * classA ->false + */ +bool TLeaveScanModel::IsClassKeyword(const string& aText, uint aBegin, uint aEnd) +{ + bool tmpBefore =false; + bool tmpAfter =false; + int len = aText.size(); + if(aBegin==0) + { + tmpBefore = true; + } + else + { + char tmpChar = aText[aBegin-1]; + if(tmpChar==' ' || tmpChar=='\n' || tmpChar=='\r' || tmpChar=='\t' || tmpChar=='{'|| tmpChar=='}'|| tmpChar==';') + { + tmpBefore = true; + } + } + if(aEnd==len-1) + { + tmpAfter = true; + } + else + { + char tmpChar = aText[aEnd+1]; + if(tmpChar==' ' || tmpChar=='\n' || tmpChar=='\r' || tmpChar=='{' || tmpChar=='('|| tmpChar==':') + { + tmpAfter = true; + } + } + return tmpAfter&&tmpBefore; +} +/** + * combine escaped lines to one line. + */ +string TLeaveScanModel::CombineLine(const string& aText) +{ + + if(aText.size()<0) return string(""); + int curPos = 0; + int curState = PPSTATE_NORMAL; + int firstPos = 0; + int stringSize = aText.size(); + int newlineCount=0; + string newText(""); + while(curPos< stringSize) + { + //remove "\" + switch(curState) + { + case PPSTATE_NORMAL: + { + char curChar=aText[curPos]; + if(curChar=='\\') + { + // '\\\n" | "\\\r" + if(stringSize>(curPos+1)&&IsNewLine(aText[curPos+1])) + { + curState= PPSTATE_ESCAPED_LINE; + newText.append(aText.substr(firstPos,curPos-firstPos)); + curPos+=1; + newlineCount+=1; + + } + else if(IsLastChar(curPos,stringSize)) + { + curPos++; + firstPos++; + } + else + { + curPos++; + } + } + else if(IsNewLine(curChar)) + { + if (newlineCount>0) + { + newText.append(aText.substr(firstPos,curPos-firstPos)); + while(newlineCount>= 0) + { + newText.append("\n"); + newlineCount--; + } + newlineCount=0; + curPos++; + firstPos=curPos; + } + else + { + curPos++; + } + } + else + { + curPos++; + } + } + break; + case PPSTATE_ESCAPED_LINE: + if(stringSize-curPos>1) + { + if( + (aText[curPos]=='\n'&&aText[curPos+1]=='\r') + || + (aText[curPos]=='\r'&&aText[curPos+1]=='\n') + ) + { + curPos+=2; + firstPos=curPos; + curState=PPSTATE_NORMAL; + } + else if(IsNewLine(aText[curPos])) + { + curPos+=1; + firstPos=curPos; + curState=PPSTATE_NORMAL; + } + } + else + { + //EOF + return newText; + } + + } + } + newText.append(aText.substr(firstPos,curPos-firstPos)); + return newText; +} + +/** + * C Preprocess + * a.remove single line comment + * b.remove mul-lines comment + * c.remove #command + * d.struct,NONSHARABLE_CLASS,NONSHARABLE_STRUCT --> class + * e.string literal -> blank string + */ +string TLeaveScanModel::PreProcess(const string& aText) +{ + string afterCombine = CombineLine(aText); + //cout<<"before:"<0&&(afterCombine[curPos-1]!='\\'&&afterCombine[curPos-1]!='\'')) + { + curState=PPSTATE_STRING_LITERAL; + newText.append(afterCombine.substr(firstPos,curPos-firstPos+1)); + + } + curPos+=1; + } + else if(curChar=='#') + { + //if # is the first non-blank char of line, comment this line + bool checkSharp=true; + for(int i=curPos-1;i>=0;i--) + { + char tmpChar = afterCombine[i]; + if(tmpChar==' '||tmpChar=='\t'||tmpChar=='\f') + { + continue; + } + else if(tmpChar=='\n' || tmpChar=='\t') + { + break; + + } + else + { + checkSharp=false; + break; + } + } + if(checkSharp) + { + curState=PPSTATE_SHARP_COMMENT; + newText.append(afterCombine.substr(firstPos,curPos-firstPos)); + } + curPos+=1; + } + //struct,NONSHARABLE_CLASS,NONSHARABLE_STRUCT --> class + else if(HasEnoughChar(curPos,stringSize,5)) + { + + if(curChar=='s'&&afterCombine[curPos+1]=='t'&&afterCombine[curPos+2]=='r'&&afterCombine[curPos+3]=='u'&&afterCombine[curPos+4]=='c'&&afterCombine[curPos+5]=='t'&&IsClassKeyword(aText,curPos,curPos+5)) + { + newText.append(afterCombine.substr(firstPos,curPos-firstPos)); + newText.append("class "); + curPos+=6; + firstPos=curPos; + } + else if(curChar=='N'&&HasEnoughChar(curPos,stringSize,11)&&afterCombine[curPos+1]=='O'&&afterCombine[curPos+2]=='N'&&afterCombine[curPos+3]=='S'&&afterCombine[curPos+4]=='H'&&afterCombine[curPos+5]=='A'&&afterCombine[curPos+6]=='R'&&afterCombine[curPos+7]=='A'&&afterCombine[curPos+8]=='B'&&afterCombine[curPos+9]=='L'&&afterCombine[curPos+10]=='E'&&afterCombine[curPos+11]=='_') + { + if(HasEnoughChar(curPos,stringSize,5)) + { + if(afterCombine[curPos+12]=='C'&&afterCombine[curPos+13]=='L'&&afterCombine[curPos+14]=='A'&&afterCombine[curPos+15]=='S'&&afterCombine[curPos+16]=='S'&&IsClassKeyword(aText,curPos,curPos+16)) + { + newText.append(afterCombine.substr(firstPos,curPos-firstPos)); + newText.append("class"); + for(int i=0;i<12;i++) + { + newText.append(" "); + } + curPos+=17; + firstPos=curPos; + break; + } + } + if(HasEnoughChar(curPos,stringSize,6)) + { + if(afterCombine[curPos+12]=='S'&&afterCombine[curPos+13]=='T'&&afterCombine[curPos+14]=='R'&&afterCombine[curPos+15]=='U'&&afterCombine[curPos+16]=='C'&&afterCombine[curPos+17]=='T'&&IsClassKeyword(aText,curPos,curPos+17)) + { + newText.append(afterCombine.substr(firstPos,curPos-firstPos)); + newText.append("class"); + for(int i=0;i<13;i++) + { + newText.append(" "); + } + curPos+=18; + firstPos=curPos; + break; + } + } + curPos++; + + }//end of nonsharable + else + { + curPos++; + } + } + + else + { + curPos++; + } + break; + } + case PPSTATE_SHARP_COMMENT: + case PPSTATE_SINGLE_COMMENT: + { + while(curPos< stringSize) + { + if(IsNewLine(afterCombine[curPos])) + { + if(stringSize-curPos>1) + { + if( + (afterCombine[curPos]=='\n'&&afterCombine[curPos+1]=='\r') + || + (afterCombine[curPos]=='\r'&&afterCombine[curPos+1]=='\n') + ) + { + curPos+=2; + } + else + { + curPos+=1; + } + firstPos=curPos; + curState=PPSTATE_NORMAL; + newText.append("\n"); + break; + } + else + { + newText.append("\n"); + return newText; + } + } + else + { + curPos++; + } + } + firstPos=curPos; + + break; + } + case PPSTATE_MUL_COMMENT: + { + blankCount=2; + while(curPos< stringSize) + { + if(!HasEnoughChar(curPos,stringSize,1)) + { + return newText; + } + if(afterCombine[curPos]=='*' && afterCombine[curPos+1]=='/') + { + curPos+=2; + firstPos=curPos; + curState=PPSTATE_NORMAL; + blankCount+=2; + break; + } + else if(IsNewLine(afterCombine[curPos])) + { + if(HasEnoughChar(curPos,stringSize,1)) + { + if( + (afterCombine[curPos]=='\n'&&afterCombine[curPos+1]=='\r') + || + (afterCombine[curPos]=='\r'&&afterCombine[curPos+1]=='\n') + ) + { + curPos+=2; + } + else + { + curPos+=1; + } + } + else + { + curPos+=1; + } + while (blankCount-->0) + { + newText.append(" "); + } + newText.append("\n"); + blankCount=0; + } + else + { + curPos++; + blankCount++; + } + } + firstPos=curPos; + while (blankCount-->0) + { + newText.append(" "); + } + blankCount=0; + + break; + } + case PPSTATE_STRING_LITERAL: + blankCount=0; + while(curPos< stringSize) + { + + if((afterCombine[curPos]=='"' )&& (afterCombine[curPos-1]!='\\')) + { + curPos+=1; + firstPos=curPos; + while (blankCount-->0) + { + newText.append(" "); + } + newText.append("\""); + curState=PPSTATE_NORMAL; + break; + } + else + { + if(curPos>1 && (afterCombine[curPos]=='"' )&& (afterCombine[curPos-1]=='\\')&&(afterCombine[curPos-2]=='\\')) + { + curPos+=1; + firstPos=curPos; + while (blankCount-->0) + { + newText.append(" "); + } + newText.append("\""); + curState=PPSTATE_NORMAL; + break; + } + else + { + curPos++; + blankCount++; + } + } + } + break; + } + } + newText.append(afterCombine.substr(firstPos,curPos-firstPos)); + return newText; +} +/* + * Get next matched '{' + */ +int TLeaveScanModel::GetLeftBracket(const string& aText,uint pos) +{ + int len =aText.size(); + if(pos>=len) + { + return string::npos; + } + while(pos=len) + { + return string::npos; + } + int parentCount = 1; + while(pos=len) + { + return string::npos; + } + while(pos=len) + { + return string::npos; + } + int parentCount = 1; + while(pos0) + { + char curChar = aText[pos]; + if(curChar=='<') + { + count--; + if (count <= 0) + return pos; + } + else if(curChar=='>') + { + count++; + } + pos--; + } + return string::npos; +} + +/* + * Get next matched '>' + */ +int TLeaveScanModel::GetRightTmpltParent(const string& aText,uint pos) +{ + int len = aText.size(); + if(pos>=len) + { + return string::npos; + } + int parentCount = 1; + while(pos' ) + { + parentCount--; + if(parentCount==0) + { + return pos; + } + } + pos++; + } + return string::npos; +} + +/* + *Get the start and end position of a class + */ +list TLeaveScanModel::GetClass(const string& aFile) +{ + int len= aFile.size(); + int startPos=0; + int nextClassPos=-1; + list classList; + //struct ,NONSHARABLE_CLASS,NONSHARABLE_STRUCT should be parsed to 'class' in pp stage + while((nextClassPos = aFile.find("class",startPos))!=string::npos) + { + + + char classSuffix = aFile[nextClassPos+5]; //the char after class + if(classSuffix!=' '&& classSuffix!='\n' && classSuffix!='\r' && classSuffix!='\t'&& classSuffix!=':'&&classSuffix!='{') + { + nextClassPos++; + startPos=nextClassPos; + continue; + } + /*no use*/ + /* + if(nextClassPos>0) + { + char classPrfix = aFile[nextClassPos-1]; + if (classPrfix =='_' || (classPrfix>='a' && classPrfix<='z') || (classPrfix>='A' && classPrfix<='Z') || (classPrfix>='0' && classPrfix<='9')) + { + nextClassPos++; + startPos=nextClassPos; + continue; + } + } + */ + if(nextClassPos >0 ) + { + char classPrefix = aFile[nextClassPos-1]; + if(classPrefix!=' '&& classPrefix!='\n' && classPrefix!='\r' && classPrefix!='\t'&& classPrefix!='{'&& classPrefix!='>'&& classPrefix!='}') + { + nextClassPos++; + startPos=nextClassPos; + continue; + } + } + + //pattern: template< ...class...> + int checkTemplate = nextClassPos-1; + bool isTemplateClass = false; + while(checkTemplate >= 0) + { + char checkTempChar = aFile[checkTemplate]; + if(checkTempChar==' '|| checkTempChar=='\n' || checkTempChar=='\r' ||checkTempChar=='\t') + { + checkTemplate --; + } + else if(checkTempChar=='>') //template<> class + { + break; + } + else if(checkTempChar=='<') + { + isTemplateClass =true; + break; + } + else if(checkTempChar==',') //template + { + isTemplateClass =true; + break; + } + else + { + break; + } + } + if(isTemplateClass) + { + startPos = nextClassPos+1; + continue; + } + + int classStart = GetLeftBracket(aFile,nextClassPos); + if(classStart==-1) + { + break; //there is no more class-body, so we can break dircetly + } + //skip this pattern + //class a; + uint semiPos = aFile.find(";",nextClassPos); + //such as this pattern: + //class a; + //class b{}; + if(semiPos!=string::npos&&semiPos= nextClassPos) + { + curClassChar = aFile[curClassNamePos]; + if(curClassChar ==' ' || curClassChar =='\t' || curClassChar =='\n' ||curClassChar=='\r' ||curClassChar==')') + { + curClassNamePos--; + } + else + { + break; + } + } + int classNameEnd = curClassNamePos; + while(curClassNamePos>=nextClassPos) + { + curClassChar = aFile[curClassNamePos]; + if(curClassChar ==' ' || curClassChar =='\t' || curClassChar =='\n' ||curClassChar=='\r'||curClassChar==':'||curClassChar=='(') + { + break; + } + else + { + curClassNamePos--; + } + } + int classNameStart = curClassNamePos+1; //cur is a blank + string curClassName = TrimString(aFile.substr(classNameStart,classNameEnd-classNameStart+1)); + if (curClassName == "class") + { + curClassName = "anonymous-class"; + } + ClassMeta curClass; + curClass.startPos=classStart; + curClass.endPos=classEnd; + curClass.className = curClassName; + classList.push_back(curClass); + startPos=nextClassPos+1; + } + return classList; +} + +/* + * parse the class and check it + * */ +void TLeaveScanModel::CheckClass(const string& aText ,const string& aClassName , uint start,uint end) +{ + start=start+1; + int curPos = start; + end=end-1; + if(end<=start) return; + //int colonCount=0; + int curStart= curPos; + int curEnd = curStart; + int curType = E_NA; + int curLine = 0; // wrong!!! + int len = aText.size(); + string functionHead=""; + string functionArgu=""; + string functionBody=""; + string memberDef=""; + + for(curPos = start;curPos<=end;curPos++) + { + char curChar = aText[curPos]; + switch(curChar) + { + case ':': + if (aText[curPos+1]==':')// a '::' + { + //skip second : + curPos+=1; + } + //such as ctor_init_list + else if(curType == E_MemberFunctionDecl || curType==E_MemberFunctionDef) + { + //nothing + } + else //such as "public:" ->ignore + { + curStart = curPos+1; + } + break; + case '{': + if(curType ==E_MemberFunctionDecl ) + { + curType = E_MemberFunctionDef; + } + else + { + curType = E_Enum; + } + curEnd = GetRightBracket(aText,curPos+1); + functionBody = aText.substr(curPos,curEnd-curPos+1); + //check in class function + if(E_MemberFunctionDef==curType) + { + CheckInClassFunc(aText,aClassName,functionHead,curPos,curEnd); + } + curPos = curEnd; + curStart =curPos; + curType = E_NA; + break; + case '(': + curType = E_MemberFunctionDecl; + curEnd = GetRightParenthesis(aText,curPos+1); + functionHead = aText.substr(curStart,curPos-curStart); + functionArgu = aText.substr(curPos,curEnd-curPos+1); + curPos = curEnd; + curStart =curPos; + + break; + case ';': + if(curType == E_NA) + { + curType = E_MemberData; + } + //check point + if (curType == E_MemberData) + { + memberDef = aText.substr(curStart,curPos-curStart); + if(memberDef.find("LCleanedup")!=string::npos) + { + iErrorString = "class "+aClassName+" defines a data member with LCleanedup* type.\n"; + cout<='0' && delimiter <='9') || (delimiter>='a' && delimiter<='z') || (delimiter>='A' && delimiter<='Z') ||(delimiter=='_'))) + { + delimiter = aText[curPos-1]; + //exclude pattern: void aclass() + if(curPos>0 && !((delimiter >='0' && delimiter <='9') || (delimiter>='a' && delimiter<='z') || (delimiter>='A' && delimiter<='Z') ||(delimiter=='_'))) + { + //pattern: template Ltemp(T x){} + uint templatePos = aText.find("template",curStart); + if(templatePos != string::npos && templatePos < curPos) + { + continue; + } + else + { + int tmpLeft = GetLeftBracket(aText,curPos+4); + int tempRight = GetRightBracket(aText,tmpLeft+1); + curPos = tempRight; + curStart = curPos; + curType = E_NA; + } + } + } + + } + } + //ignore + break; + default: + //curPos++; + break; + } + //curPos++; + } +} +/* + * Is a ctor of L class + * */ +bool TLeaveScanModel::IsLClassCtor(const string& aName) +{ + + //if(aName[0]=='L'&&aName.find("::")!=string::npos)% + //{ + // return true; + //} + uint colonPos = aName.find("::"); + if(colonPos == string::npos) + { + return false; + } + string s1 = aName.substr(0,colonPos); + string s2 = aName.substr(colonPos+2); + s1.erase(s1.find_last_not_of(" \t\n\r")+1); + s1.erase(0,s1.find_first_not_of(" \t\n\r")); + + s2.erase(s2.find_last_not_of(" \t\n\r")+1); + s2.erase(0,s2.find_first_not_of(" \t\n\r")); + + + uint tmpltPos = s1.find('<'); + if(tmpltPos!=string::npos) + { + s1 = s1.substr(0,tmpltPos); + } + if(s1[0]!='L') + { + return false; + } + if(s1.find(s2)!=string::npos) + { + uint s1Len = s1.length(); + uint s2Len = s2.length(); + //s1=LAL + //s2=LA + if(s2Len>0 && s1Len > s2Len) + { + char diffChar = s1[s2Len]; + if( (diffChar>='a' && diffChar<='z') || (diffChar>='A' && diffChar<='Z') + ||(diffChar>='0' && diffChar<='9') || (diffChar=='_')) + { + return false; + } + } + return true; + } + if(s2.find("operator")==0) + { + return true; + } + if(s2.find("new")==0) + { + return true; + } + + return false; +} +/* +* Is sometiing defined in class scope? +*/ +bool TLeaveScanModel::IsInClassScope(uint pos) +{ + if (pos == string::npos) + { + return false; + } + list::iterator iter; + for(iter=iClassList.begin();iter!=iClassList.end();iter++) + { + if(iter->startPos<=pos && iter->endPos >= pos) + { + return true; + } + } + return false; + +} +/* + * Try to get the function name from a function head + * */ +string TLeaveScanModel::GetFunctNameFromFuncHead(const string& aFuncHead) +{ + string funcName; + int len = aFuncHead.length(); + int curPos=len-1; + char curChar; + int nameStart = -1; + int nameEnd; + //skip white spaces + while(curPos>=0) + { + curChar = aFuncHead[curPos]; + if(curChar==' ' || curChar=='\t' ||curChar=='\n'||curChar=='\r') + { + curPos--; + } + else + { + break; + } + } + if(curChar == '>') + { + int templateBalance = 1; + curPos--; + while(curPos>=0) + { + curChar = aFuncHead[curPos]; + + if(curChar=='>') + { + templateBalance++; + } + else if(curChar =='<') + { + templateBalance--; + } + curPos--; + if(templateBalance==0) + { + break; + } + + } + } + if(curPos<=0) return ""; + + nameEnd = curPos; + if(aFuncHead.find("operator")!=string::npos) + { + int tmpNameStart = aFuncHead.find("operator"); + char delimiter = aFuncHead[tmpNameStart+8]; + if (!((delimiter >='0' && delimiter <='9') || (delimiter>='a' && delimiter<='z') || (delimiter>='A' && delimiter<='Z') ||(delimiter=='_'))) + { + if(tmpNameStart>0) + { + delimiter = aFuncHead[tmpNameStart-1]; + if (!((delimiter >='0' && delimiter <='9') || (delimiter>='a' && delimiter<='z') || (delimiter>='A' && delimiter<='Z') ||(delimiter=='_'))) + { + nameStart = tmpNameStart; + } + } + if(tmpNameStart==0) + { + nameStart = tmpNameStart; + } + } + } + if(nameStart == -1) + { + while(curPos>=0) + { + curChar = aFuncHead[curPos]; + if(curChar==' ' || curChar=='\t' ||curChar=='\n'||curChar=='\r'||curChar=='>') + { + nameStart = curPos+1; + if(nameStart<0) + { + nameStart = 0; + } + break; + + } + else + { + curPos--; + } + + } + if(curPos<0) + { + nameStart = 0; + } + } + funcName = aFuncHead.substr(nameStart,nameEnd-nameStart+1); + return funcName; + + +} +/* + * Get the Param string of a function decl + * aStart usually is the position of '{' + * */ +string TLeaveScanModel::GetFunctionParam(const string& aText, uint aStart) +{ + int curPos = aStart; + if(curPos == string::npos) + { + return ""; + } + int leftParenthesis = GetLeftParenthesis(aText, curPos); + int rightParenthesis = GetRightParenthesis(aText, leftParenthesis+1); + + if(leftParenthesis==string::npos || rightParenthesis==string::npos) + { + return ""; + } + else if(rightParenthesis>leftParenthesis) + { + return aText.substr(leftParenthesis+1, rightParenthesis-leftParenthesis-1); + } + return ""; + + +} + +/*Get the string from last member decl to aStart*/ +string TLeaveScanModel::GetFunctionHead(const string& aText, uint aStart) +{ + int curPos = aStart; + char curChar; + if(curPos==string::npos || curPos<=0) + { + return ""; + } + while(curPos >= 0) + { + curChar = aText[curPos]; + if(curChar == '{' || curChar == '}' || curChar == ';') + { + break; + } + curPos--; + } + if(curPos<0) + { + curPos = 0; + } + + int tempPos = string::npos; + if( (aText.rfind("public",aStart)!=string::npos)||(aText.rfind("protected",aStart))!=string::npos ||(aText.rfind("private",aStart))!=string::npos) + { + tempPos = aText.rfind(':',aStart); + + } + if(tempPos>curPos) + { + curPos = tempPos; + } + return aText.substr(curPos,aStart-curPos); + +} +/*Chech the function decl/define in a class*/ +void TLeaveScanModel::CheckInClassFunc(const string& aText , const string& aClassName, const string& aFuncName, uint start,uint end) +{ + bool isLeaver; + bool clean; + string funcName = TrimString(GetFunctNameFromFuncHead(aFuncName)); + string qualifiedFuncName = aClassName+"::"+funcName; + clean = CheckFunc(aText, funcName, start, end, isLeaver); + bool isLCFunc =false; + if(funcName[funcName.length()-1] == 'C' && funcName[funcName.length()-2] == 'L') + { + isLCFunc = true; + } + if (isLeaver) // was a leaving container(safe) and no leavers found + { + + if (clean) + { + iPositionOfError=0; + iErrorString = "Warning - " + funcName + " appears to contain no leavers."; + ReportErrorLineAndString(start); + } + else if(isLCFunc) + { + + uint lcleanedupPos = iErrorString.find("LCleanedup"); + if(lcleanedupPos!=string::npos) + { + uint callPos = iErrorString.find(" calls "); + uint lcleanedupPosInFuncName = funcName.find("LCleanedup"); + if(callPos!=string::npos && lcleanedupPosInFuncName!=string::npos && lcleanedupPos