|
1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // Limitations: |
|
15 // Leavescan will attempt to avoid comments, strings and char literals which it |
|
16 // finds within the code. It is also capable of recognising escaped quotes, |
|
17 // but complex combinations of escaping e.g. "\\\"\"\'" may fool the parser and |
|
18 // result in false positives, or cause parsing to terminate prematurely (resulting |
|
19 // in possible unreported problems. |
|
20 // Leavescan can only parse what it sees, and is therefore oblivious to any |
|
21 // non-trivial attempt to call a leaving function (i.e. by function pointer) |
|
22 // Macros can also fool the parser (as is), but leavscan will now indicate |
|
23 // whether the leaving invocation may, in fact, be a macro. |
|
24 // Multiple files are now supported on the command-line, along with some basic |
|
25 // options such as '-v' which will dump the version. Invoking with no |
|
26 // parameters will dump the version & help, so that automated build systems can |
|
27 // check the version and cater for enhanced behaviour. |
|
28 // Local Version: |
|
29 // $Id: leavescan2.cpp,v 1.6 2003/02/19 12:59:00 AndrewHa Exp $ |
|
30 // |
|
31 // |
|
32 |
|
33 |
|
34 #include <fstream> |
|
35 #include <iostream> |
|
36 #include <sstream> |
|
37 #include <string> |
|
38 #include <assert.h> |
|
39 #include <list> |
|
40 |
|
41 #define FOREVER for(;;) |
|
42 |
|
43 //static const char Kversion[] = "0.06"; // Version updated 07 March 08 |
|
44 static const char Kversion[] = "0.07"; // suprrot L class, fix some defects.Version updated 07/2008 |
|
45 // Shorthand |
|
46 typedef unsigned int uint; |
|
47 |
|
48 // Set of match types. E_Last must be at the end of the list. |
|
49 enum TMatchTypes { |
|
50 E_LCleanedUp=0, |
|
51 E_LString, |
|
52 E_LManaged, |
|
53 E_LData, |
|
54 E_Ell , |
|
55 E_Trap, |
|
56 E_BlockComment, |
|
57 E_LineComment, |
|
58 E_Eleave, |
|
59 E_UserEleave, |
|
60 E_String, |
|
61 E_Quote, |
|
62 E_OpenBrace, |
|
63 E_CloseBrace, |
|
64 E_OrLeave, |
|
65 E_Last }; |
|
66 |
|
67 // Set of return values of GetFunc(). |
|
68 enum TReturnTypes { |
|
69 E_False = 0, |
|
70 E_True, |
|
71 E_Continue }; |
|
72 |
|
73 enum TPPState { |
|
74 PPSTATE_NORMAL=0, |
|
75 PPSTATE_ESCAPED_LINE , |
|
76 PPSTATE_SINGLE_COMMENT, |
|
77 PPSTATE_MUL_COMMENT, |
|
78 PPSTATE_STRING_LITERAL, |
|
79 PPSTATE_SHARP_COMMENT |
|
80 }; |
|
81 |
|
82 enum TClassMemberTypes { |
|
83 E_NA= 0, |
|
84 E_MemberData, |
|
85 E_MemberFunctionDecl, |
|
86 E_MemberFunctionDef, |
|
87 E_Enum |
|
88 }; |
|
89 |
|
90 using namespace std; |
|
91 struct ClassMeta { |
|
92 string className ; |
|
93 int startPos; |
|
94 int endPos; |
|
95 }; |
|
96 |
|
97 class TLeaveScanModel |
|
98 { |
|
99 public: |
|
100 bool Scan(ifstream& aStream); |
|
101 void SetFileName(char* aName); |
|
102 char* FileName(); |
|
103 int Verbose; |
|
104 bool OnlyPrePrecess; |
|
105 |
|
106 private: |
|
107 void FileToText(ifstream& aStream, string& aText); |
|
108 enum TReturnTypes GetFunc(const string& aFile, string &name, uint &start, uint &end); |
|
109 bool CheckFunc(const string& aFile, string& aName, uint start, uint end, bool& aIsLeaver); |
|
110 bool MoveToEndOfTrapHarness(const string& aStr, uint& aIndex, uint aLen); |
|
111 void MoveToEndOfComment(const string& aStr, uint& aIndex, uint aLen); |
|
112 void MoveToEndOfLine(const string& aStr, uint& aIndex, uint aLen); |
|
113 void MoveToEndOfString(const string& aStr, uint& aIndex, uint aLen, char aQuote); |
|
114 uint GetRealStartPosition(const string& aFile, uint aStart, uint aIsvalidDoublecolon); |
|
115 void Peek(const string aStr, uint aPos); |
|
116 uint SmartFind(const string& aStr, const string& aTarget, uint aStart); |
|
117 uint SmartFindEndOfString(const string& aStr, uint aPos, char aQuote); |
|
118 bool IsInCommentScopeOrKeyword(const string& aFile, string &aName, uint aStartposition, uint aStartbraceposn); |
|
119 bool IsFunctionNameStringNotAMacro(const string& aFile, uint aStartbraceposn, uint aTempParenPos, uint aNstart); |
|
120 bool IsSemiColonAndAssignmentOccurs(const string& aFile, uint aStartbraceposn, uint aTempParenPos); |
|
121 bool CheckValidFuncName(const string& aFile, uint aStart); |
|
122 bool CheckForTemplateFunc(const string& aFile, uint nstart, uint nend); |
|
123 uint FindFirstMatchType(uint aMatchSet[]); |
|
124 string PreProcess(const string& aFile); |
|
125 string CombineLine(const string& aFile); |
|
126 list<ClassMeta> GetClass(const string& aFile); |
|
127 int GetLeftParenthesis(const string& aText, uint pos); |
|
128 int GetRightParenthesis(const string& aText, uint pos); |
|
129 int GetLeftTmpltParentBack(const string& aText,uint pos); |
|
130 int GetRightTmpltParent(const string& aText,uint pos); |
|
131 bool IsClassKeyword(const string& aText, uint aBegin, uint aEnd); |
|
132 int GetLeftBracket(const string& aText,uint pos); |
|
133 int GetRightBracket(const string& aText,uint pos); |
|
134 void CheckClass(const string& aText , const string& aClassName, uint start,uint end); |
|
135 void CheckInClassFunc(const string& aText , const string& aClassName, const string& aFuncName, uint start,uint end); |
|
136 bool IsLClassCtor(const string& aName); |
|
137 bool IsInClassScope(uint pos); |
|
138 string GetFunctNameFromFuncHead(const string& aFuncHead); |
|
139 string GetFunctionParam(const string& aText, uint aStart); |
|
140 string GetFunctionHead(const string& aText, uint aStart); |
|
141 string GetErrorLineHead(const string& aText,uint aStart); |
|
142 string GetClassName(uint aStart); |
|
143 void ReportErrorLineAndString(uint aStart); |
|
144 bool AppendCommentToErrorString(uint aEnd); |
|
145 bool IdentifyMacro(const string& str, const uint aPos); |
|
146 void Test1(); |
|
147 void Test2L(); |
|
148 void Test3(); |
|
149 void Test4(); |
|
150 |
|
151 inline bool IsNewLine(const char& aCurChar) {return ((aCurChar)=='\n'||(aCurChar)=='\r')?true:false;} |
|
152 inline bool IsLastChar(uint aCurPos, uint aStringLength) { return ((aCurPos+1)==aStringLength)?true:false;} |
|
153 inline bool HasEnoughChar(uint aCurPos,uint aStringLength,uint aWanted) {return (aStringLength-aCurPos-1>=aWanted)?true:false;} |
|
154 inline string TrimString(const string& aStr) |
|
155 { |
|
156 string result = aStr; |
|
157 result.erase(result.find_last_not_of(" \t\n\r")+1); |
|
158 result.erase(0,result.find_first_not_of(" \t\n\r")); |
|
159 return result; |
|
160 } |
|
161 private: |
|
162 string iText; |
|
163 string iBody; |
|
164 string iErrorString; |
|
165 list<ClassMeta> iClassList; |
|
166 int iPositionOfError; |
|
167 char* iFileName; |
|
168 |
|
169 }; |
|
170 |
|
171 void pversion() |
|
172 { |
|
173 cout << "Leavescan version: " << Kversion <<"(build time:"<<__DATE__<<" "<<__TIME__<<")\n"; |
|
174 } |
|
175 |
|
176 void pusage() |
|
177 { |
|
178 pversion(); |
|
179 cout << "syntax: \n\tleavescan [-h|-n|-v|-N] <iFilename.cpp> [<iFilename.cpp> ...]\n\n"; |
|
180 cout << "\t-h: This help.\n"; |
|
181 cout << "\t-n: Noisy output - provides diagnostics (if available).\n"; |
|
182 cout << "\t-N: Very noisy output - provides diagnostics (if available).\n"; |
|
183 cout << "\t-v: Displays version (for build & automation systems).\n"; |
|
184 cout << "\t-E: Only do pre-process\n\n"; |
|
185 |
|
186 } |
|
187 |
|
188 int main(int argc, char** argv) |
|
189 { |
|
190 int noisy = 0; |
|
191 bool onlyPreProcess =false; |
|
192 if (argc < 2) |
|
193 { |
|
194 pusage(); |
|
195 return 1; |
|
196 } |
|
197 |
|
198 for (int clparam = 1; clparam < argc; clparam++) |
|
199 { |
|
200 if (argv[clparam][0] == '-') |
|
201 { |
|
202 switch(argv[clparam][1]) |
|
203 { |
|
204 case 'n': |
|
205 noisy = 1; |
|
206 break; |
|
207 case 'N': |
|
208 noisy = 2; |
|
209 break; |
|
210 case 'h': |
|
211 pusage(); |
|
212 break; |
|
213 case 'v': |
|
214 pversion(); |
|
215 break; |
|
216 case 'E': |
|
217 { |
|
218 onlyPreProcess = true; |
|
219 } |
|
220 break; |
|
221 default: |
|
222 pusage(); |
|
223 break; |
|
224 } |
|
225 } //if |
|
226 else |
|
227 { |
|
228 // invoked once per file |
|
229 TLeaveScanModel model; |
|
230 model.SetFileName(argv[clparam]); |
|
231 model.Verbose = noisy; |
|
232 if(onlyPreProcess) |
|
233 { |
|
234 model.OnlyPrePrecess = true; |
|
235 } |
|
236 else |
|
237 { |
|
238 model.OnlyPrePrecess = false; |
|
239 } |
|
240 ifstream file(model.FileName()); |
|
241 (void) model.Scan(file); |
|
242 file.close(); |
|
243 // return 0; |
|
244 } |
|
245 } |
|
246 return 0; |
|
247 } |
|
248 |
|
249 void TLeaveScanModel::SetFileName(char *aName) |
|
250 { |
|
251 iFileName = aName; |
|
252 } |
|
253 |
|
254 char* TLeaveScanModel::FileName() |
|
255 { |
|
256 return iFileName; |
|
257 } |
|
258 |
|
259 // |
|
260 // Main processing function which converts the file to a basic::string |
|
261 // and then searches through for methods, analysing them as they are |
|
262 // located. |
|
263 bool TLeaveScanModel::Scan(ifstream& aStream) |
|
264 { |
|
265 FileToText(aStream, iText); |
|
266 string oldText(iText); |
|
267 iText = PreProcess(iText); |
|
268 if(OnlyPrePrecess) |
|
269 { |
|
270 cout<<iText; |
|
271 return false; |
|
272 } |
|
273 if(!iText.length()) |
|
274 { |
|
275 cout << "File not found or empty.\n"; |
|
276 return false; |
|
277 } |
|
278 |
|
279 uint start = 0; |
|
280 uint end = 0; |
|
281 bool isLeaver; |
|
282 enum TReturnTypes getFuncReturnTypes; |
|
283 //init class list |
|
284 iClassList = GetClass(iText); |
|
285 //check function |
|
286 while (start < iText.length()) |
|
287 { |
|
288 string name; |
|
289 getFuncReturnTypes = E_Continue; |
|
290 while(getFuncReturnTypes == E_Continue) |
|
291 { |
|
292 getFuncReturnTypes = GetFunc(iText, name, start, end); |
|
293 } |
|
294 if (!getFuncReturnTypes) |
|
295 break; |
|
296 |
|
297 bool clean = CheckFunc(iText, name, start, end, isLeaver); |
|
298 bool isLCFunc =false; |
|
299 if(name[name.length()-1] == 'C' && name[name.length()-2] == 'L') |
|
300 { |
|
301 isLCFunc = true; |
|
302 } |
|
303 if (isLeaver) // was a leaving container(safe) and no leavers found |
|
304 { |
|
305 |
|
306 if (clean) |
|
307 { |
|
308 iPositionOfError=0; |
|
309 iErrorString = "Warning - " + name + " appears to contain no leavers."; |
|
310 if(!IsInClassScope(start)) |
|
311 { |
|
312 ReportErrorLineAndString(start); |
|
313 } |
|
314 } |
|
315 else if(isLCFunc) |
|
316 { |
|
317 |
|
318 uint lcleanedupPos = iErrorString.find("LCleanedup"); |
|
319 if(lcleanedupPos!=string::npos) |
|
320 { |
|
321 uint callPos = iErrorString.find(" calls "); |
|
322 uint lcleanedupPosInFuncName = name.find("LCleanedup"); |
|
323 if(callPos!=string::npos && lcleanedupPosInFuncName!=string::npos && lcleanedupPos<callPos) |
|
324 {;} |
|
325 else |
|
326 { |
|
327 iErrorString = "LCleanedup class is used in a function suffixed LC"; |
|
328 if(!IsInClassScope(start)) |
|
329 { |
|
330 ReportErrorLineAndString(start); |
|
331 } |
|
332 } |
|
333 } |
|
334 } |
|
335 |
|
336 // any leavers info can be supressed here since container was leaver |
|
337 } |
|
338 else // wasn't a leaving container |
|
339 { |
|
340 if (!clean) // was dirty, so report |
|
341 if(!IsInClassScope(start)) |
|
342 { |
|
343 ReportErrorLineAndString(start); |
|
344 } |
|
345 } |
|
346 start = end; |
|
347 } |
|
348 //check class |
|
349 list<ClassMeta>::iterator iter; |
|
350 for(iter=iClassList.begin();iter!=iClassList.end();iter++) |
|
351 { |
|
352 CheckClass(iText,iter->className,iter->startPos,iter->endPos); |
|
353 } |
|
354 return true; |
|
355 } |
|
356 |
|
357 // |
|
358 // Spool a file into one large basic::string |
|
359 // |
|
360 void TLeaveScanModel::FileToText(ifstream& aStream, string& aText) |
|
361 { |
|
362 char data[1024]; |
|
363 int len; |
|
364 do |
|
365 { |
|
366 aStream.read(data,1024); |
|
367 len = aStream.gcount(); |
|
368 aText.append(data, len); |
|
369 } |
|
370 while(len); |
|
371 } |
|
372 |
|
373 // To get the actual position of starting parenthesis for a function definition |
|
374 // |
|
375 uint TLeaveScanModel::GetRealStartPosition(const string& aFile,uint aStart, uint aIsvaliddoublecolon) |
|
376 { |
|
377 uint realstartpos = 0; |
|
378 |
|
379 // The opening parenthesis which comes fist after opening brace while moving |
|
380 // in backward direction is a valid candidate for function name. |
|
381 |
|
382 uint firstcurlybrace = SmartFind(aFile, "{", aStart + 1 ); // advance start |
|
383 |
|
384 if ((firstcurlybrace == string::npos) || (firstcurlybrace >= aFile.length())) |
|
385 { |
|
386 return realstartpos; |
|
387 } |
|
388 |
|
389 // This variable will store the first paranthesis position |
|
390 uint tempParenPos = aFile.find_last_of('(',firstcurlybrace); |
|
391 |
|
392 if (tempParenPos == string::npos) |
|
393 { |
|
394 // No '(' found yet |
|
395 return realstartpos; |
|
396 } |
|
397 |
|
398 if (aIsvaliddoublecolon == 1) |
|
399 { |
|
400 tempParenPos = aStart; |
|
401 } |
|
402 |
|
403 string whiteSpaceChars = " \t\n\r*&"; |
|
404 |
|
405 // ignore all tab and spaces between function name and opening parenthesis |
|
406 uint nend = aFile.find_last_not_of(whiteSpaceChars, --tempParenPos); |
|
407 uint pos = aFile.find_last_of(whiteSpaceChars, nend); |
|
408 |
|
409 if (pos == string::npos) |
|
410 { |
|
411 return realstartpos; |
|
412 } |
|
413 else |
|
414 { |
|
415 return pos; |
|
416 } |
|
417 } |
|
418 /* |
|
419 This function checks the following : |
|
420 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) |
|
421 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' |
|
422 |
|
423 @internalComponent |
|
424 @released |
|
425 @param aFile - Buffer storing the whole source file contents(input) |
|
426 @param aName - String that is to be checked whether it lies in the scope of the comment(input) |
|
427 @param aStartposition - Starting offset of name in file.(input) |
|
428 @param aStartbraceposn - Starting offset of function block (input) |
|
429 @param true - if name is in comment scope(output) |
|
430 @param false - if name is not in comment scope |
|
431 |
|
432 |
|
433 Following patterns are handled in this function: |
|
434 ----------------------------------------------- |
|
435 NOTE: in order to remove compile warning, i use "|" stand for "/" in this section of comment |
|
436 |
|
437 Pattern 1: String is in the scope of both c-style and C++-style comments |
|
438 |
|
439 |* |
|
440 || name1 |
|
441 * | |
|
442 |
|
443 |
|
444 Pattern 2: String is in the scope of both c-style comments |
|
445 |
|
446 |* |
|
447 name2() |
|
448 * | |
|
449 |
|
450 Pattern 3: String is in comment scope and the comment scope llies in a string |
|
451 |
|
452 printf(" |* * | || ") |
|
453 |
|
454 |
|
455 Pattern 4: String is in the scope of C++-style comments but C-style comments is also available in souurce file |
|
456 |
|
457 |* |
|
458 |
|
459 * | |
|
460 |
|
461 || function() |
|
462 |
|
463 |
|
464 |
|
465 Pattern 5: String is in the scope of C-style comments but C+++-style comments is also available in souurce file |
|
466 |
|
467 || function() |
|
468 |* |
|
469 |
|
470 * | |
|
471 |
|
472 |
|
473 Pattern 6: The string is a keyword and the program construct for the keyword is same as for the functions |
|
474 for() |
|
475 { } |
|
476 |
|
477 |
|
478 Pattern 7: Both C-style and C++-style comments are avialable in file and the way of specifying comments |
|
479 is complex.(i.e. it is difficult to identify whether it is a C-Style comment or C++-style comment |
|
480 ||******* |
|
481 fun() |
|
482 |****** |
|
483 **** | |
|
484 {} |
|
485 |
|
486 */ |
|
487 bool TLeaveScanModel::IsInCommentScopeOrKeyword(const string& aFile, string &aName, uint aStartposition,uint aStartbraceposn) |
|
488 { |
|
489 uint blockCommentStartPosn = aFile.rfind("/*",aStartposition); // In backward direction |
|
490 uint lineCommentStartPosn = aFile.rfind("//",aStartposition); |
|
491 uint blockCommentEndPosn = aFile.find("*/", aStartposition); // In forward direction |
|
492 uint semicolon = aFile.rfind(";",aStartposition); |
|
493 uint isvalidlocationforBlock; |
|
494 uint isvalidlocationforLine ; |
|
495 |
|
496 if( (0 == strcmp(aName.c_str(),"if")) || (0 == strcmp(aName.c_str(),"while")) || |
|
497 (0 == strcmp(aName.c_str(),"for"))|| (0 == strcmp(aName.c_str(),"switch")) || |
|
498 (0 == strcmp(aName.c_str(),"defined"))) |
|
499 { |
|
500 return true; |
|
501 } |
|
502 // There is no comment of any type either block comment or line comment |
|
503 if(blockCommentStartPosn == string::npos && lineCommentStartPosn == string::npos) |
|
504 { |
|
505 return false; |
|
506 } |
|
507 // A semiclon exists and semicolon is followed by both (1) the end of block comment scope and (2) the end of line comment scope |
|
508 else if((semicolon != string::npos)&& |
|
509 ((semicolon > blockCommentEndPosn) && (blockCommentStartPosn < blockCommentEndPosn)) && |
|
510 (semicolon > lineCommentStartPosn)) |
|
511 { |
|
512 return false; |
|
513 } |
|
514 else if(lineCommentStartPosn == string::npos) |
|
515 { |
|
516 // Valid Block comment, verify that the function name by applying smartfind |
|
517 isvalidlocationforBlock = SmartFind(aFile, aName, blockCommentStartPosn); |
|
518 if( (isvalidlocationforBlock == string::npos) || // There is no occurrence of name |
|
519 ((isvalidlocationforBlock > aStartbraceposn) && (isvalidlocationforBlock != string::npos))) // The name exists but that is inside function block |
|
520 { |
|
521 return true; |
|
522 } |
|
523 else |
|
524 { |
|
525 return false; |
|
526 } |
|
527 } |
|
528 else if(blockCommentStartPosn == string::npos) |
|
529 { |
|
530 isvalidlocationforLine = SmartFind(aFile,aName, lineCommentStartPosn); |
|
531 if( (isvalidlocationforLine == string::npos) || // There is no occurrence of name |
|
532 ((isvalidlocationforLine > aStartbraceposn) && (isvalidlocationforLine != string::npos) ) ) // The name exists but that is inside function block |
|
533 { |
|
534 return true; |
|
535 } |
|
536 else |
|
537 { |
|
538 return false; |
|
539 } |
|
540 } |
|
541 else |
|
542 { |
|
543 isvalidlocationforBlock = SmartFind(aFile,aName, blockCommentStartPosn); |
|
544 isvalidlocationforLine = SmartFind(aFile,aName, lineCommentStartPosn); |
|
545 if((isvalidlocationforLine == string::npos) ) |
|
546 { |
|
547 return true; |
|
548 } |
|
549 else if(( (isvalidlocationforLine > aStartbraceposn) && (isvalidlocationforLine != string::npos)) ) |
|
550 { |
|
551 return true; |
|
552 } |
|
553 else if( (0 == isvalidlocationforBlock) || ((isvalidlocationforBlock > aStartbraceposn) && (isvalidlocationforBlock != string::npos)) ) |
|
554 { |
|
555 return true; |
|
556 } |
|
557 else if(( blockCommentStartPosn < aStartbraceposn) && (blockCommentEndPosn < aStartbraceposn ) && (blockCommentStartPosn < blockCommentEndPosn) && ((isvalidlocationforBlock == string::npos))) |
|
558 { |
|
559 return true; |
|
560 } |
|
561 else |
|
562 { |
|
563 return false; |
|
564 } |
|
565 } |
|
566 } |
|
567 |
|
568 /* |
|
569 This function checks whether the function name is a macro or not |
|
570 |
|
571 @internalComponent |
|
572 @released |
|
573 @param aFile - Buffer storing the whole source file contents |
|
574 @param aStartbraceposn - Starting offset of function block (input) |
|
575 @param aParenPos - End position of function signature |
|
576 @param aStartposnofname - Starting offset of string that is to be considered as a function name |
|
577 @param true - If function name is not a macro |
|
578 @param false - If function name is a macro |
|
579 |
|
580 Following patterns are handled in this function: |
|
581 ----------------------------------------------- |
|
582 |
|
583 Pattern 1: Function is invoked in macro |
|
584 |
|
585 #if defined macro() |
|
586 #endif |
|
587 struct s1 |
|
588 { |
|
589 |
|
590 } |
|
591 |
|
592 Pattern 2: Function is invoked in macro but the macro itself is in comment scope |
|
593 void fun() |
|
594 // #if macro() |
|
595 // #endif |
|
596 { |
|
597 struct s1 |
|
598 { |
|
599 |
|
600 } |
|
601 } |
|
602 |
|
603 Pattern 3: There is parameterized Constructor e.g. |
|
604 |
|
605 Foobar(CFileMan* aFileMan) : iFileMan(aFileMan), iCurrentStep(0) {} |
|
606 |
|
607 |
|
608 Pattern 4: Function is defined on the preprocessor statement e.g |
|
609 |
|
610 #define __KTRACE_ALL(a,p) {if((DEBUGMASK&(a))==(a))p;} |
|
611 |
|
612 Pattern 5: All the functions name in comment scope will be ignored |
|
613 |
|
614 void func() |
|
615 // #if comments() |
|
616 { |
|
617 |
|
618 } |
|
619 |
|
620 Pattern 6: All the functions name (e.g. comments) in comment scope will be ignored |
|
621 |
|
622 #if defined() |
|
623 // comments() |
|
624 struct{ |
|
625 } |
|
626 |
|
627 */ |
|
628 |
|
629 bool TLeaveScanModel::IsFunctionNameStringNotAMacro(const string& aFile, uint aStartbraceposn, uint aParenPos, uint aStartposnofname) |
|
630 { |
|
631 uint startofword = 0; |
|
632 uint endofword = 0; |
|
633 uint tempParenPos = 0; |
|
634 bool posn = true; |
|
635 string whiteSpaceChars = " \t\n\r"; |
|
636 uint tempColonPosn = SmartFind(aFile,":",aParenPos); |
|
637 string colonString(":"); |
|
638 bool isColonInCommentScope = IsInCommentScopeOrKeyword(aFile,colonString,aParenPos,aStartbraceposn); |
|
639 if( (tempColonPosn != string::npos) && |
|
640 (false == isColonInCommentScope) && |
|
641 (tempColonPosn < aStartbraceposn) ) |
|
642 { |
|
643 return true; // Not a macro |
|
644 } |
|
645 // The function ignores all the strings which are in the scope of block comments. |
|
646 while( startofword < aStartbraceposn && endofword < aStartbraceposn && posn == true) |
|
647 { |
|
648 if(tempParenPos == 0) |
|
649 { |
|
650 tempParenPos = aParenPos; // First word |
|
651 } |
|
652 else |
|
653 { |
|
654 tempParenPos = endofword; // Next word |
|
655 } |
|
656 startofword = aFile.find_first_not_of(whiteSpaceChars, tempParenPos+1); |
|
657 if(startofword != aStartbraceposn) // No string between function signature and function start block |
|
658 { |
|
659 // get the posn of word end boundary |
|
660 endofword = aFile.find_first_of(whiteSpaceChars, startofword); |
|
661 string tmpString = aFile.substr(startofword,endofword-startofword); |
|
662 string &aName = tmpString; |
|
663 //is throw? |
|
664 if(0==aName.find("throw")) |
|
665 { |
|
666 return true; |
|
667 } |
|
668 if( (0 == strcmp(aName.c_str(),"const")) || |
|
669 (0 == strncmp(aName.c_str(),"//",2)) || |
|
670 (0 == strncmp(aName.c_str(),"*/",2)) || |
|
671 (0 == strncmp(aName.c_str(),"/*",2)) ) |
|
672 { |
|
673 // do nothing |
|
674 } |
|
675 else |
|
676 { |
|
677 // If string is in comment scope then it is fine i.e. the function returns true; |
|
678 posn = IsInCommentScopeOrKeyword(aFile,aName,startofword,aStartbraceposn); |
|
679 } |
|
680 } |
|
681 else |
|
682 { |
|
683 // Pattern 1: only spaces are there between ')' and '{' e.g. void fun() {} |
|
684 posn = true; |
|
685 } |
|
686 } |
|
687 if(posn == false) |
|
688 { |
|
689 return false; |
|
690 } |
|
691 uint endOfLine=aFile.rfind('\n',aStartposnofname); // Get the new line position while backtracking |
|
692 uint aIndex=(endOfLine==string::npos ? 0 : endOfLine); |
|
693 uint preprocessorDirective = aFile.rfind("#",aStartposnofname); // Get the first char of the line starting with # |
|
694 if(preprocessorDirective != string::npos && aIndex <= preprocessorDirective) |
|
695 { |
|
696 return false; // // Yes, the first char is #, so the name on this line can not be a valid function name |
|
697 } |
|
698 // Check whether it is a macro |
|
699 return true; |
|
700 } |
|
701 |
|
702 |
|
703 |
|
704 /* |
|
705 This function checks whether any semocolon (';') or assignment(=) is encountered |
|
706 when the backtracking is done to look for function name. |
|
707 |
|
708 @internalComponent |
|
709 @released |
|
710 @param aFile - Buffer storing the whole source file contents |
|
711 @param aStartbraceposn - Starting offset of function block (input) |
|
712 @param aTempParenPos - End position of function signature |
|
713 @param true - if either assignment expression '=' or ':' occurs between function signature and starting curly brace of function block. |
|
714 @param false - if neither assignment expression '=' nor ':' occurs between function signature and starting curly brace of function block. |
|
715 |
|
716 |
|
717 Following patterns are handled in this function: |
|
718 ----------------------------------------------- |
|
719 |
|
720 Pattern 1: The semicolon is encountered while backtracking in the search of function name |
|
721 |
|
722 _LT(); |
|
723 struct s1 |
|
724 { |
|
725 |
|
726 } |
|
727 |
|
728 Pattern 2: The semicolon is encountered while backtracking in the search of function name |
|
729 |
|
730 fun(); |
|
731 a = 2; |
|
732 struct str1 |
|
733 { |
|
734 |
|
735 } |
|
736 |
|
737 Pattern 3: The assignment is encountered while backtracking in the search of function name |
|
738 |
|
739 voidmain() |
|
740 a[2] = |
|
741 { |
|
742 1,2,3 |
|
743 } |
|
744 |
|
745 */ |
|
746 |
|
747 bool TLeaveScanModel::IsSemiColonAndAssignmentOccurs(const string& aFile,uint aStartbraceposn ,uint aTempParenPos) |
|
748 { |
|
749 string semicolon(";"); |
|
750 string assignment("="); |
|
751 uint tempSemicolonPosn = SmartFind(aFile,semicolon,aTempParenPos-1); |
|
752 //uint tempAssignMentPosn = SmartFind(aFile,assignment,aTempParenPos-1); |
|
753 bool isSemicolonInCommentScope = IsInCommentScopeOrKeyword(aFile,semicolon,aTempParenPos,aStartbraceposn); |
|
754 bool isAssignmentInCommentScope = IsInCommentScopeOrKeyword(aFile,assignment,aTempParenPos,aStartbraceposn); |
|
755 if( (tempSemicolonPosn != string::npos) && |
|
756 ((false == isSemicolonInCommentScope) || (false == isAssignmentInCommentScope)) && |
|
757 (tempSemicolonPosn < aStartbraceposn) |
|
758 ) |
|
759 { |
|
760 return false; |
|
761 } |
|
762 return true; |
|
763 } |
|
764 |
|
765 /* |
|
766 This function checks whether the function definition is terminated by semi colon |
|
767 |
|
768 If the function definition is terminated with semicolon, then it is |
|
769 more likely to be a class/struct declaration rather than a function definition. |
|
770 |
|
771 @internalComponent |
|
772 @released |
|
773 @param aFile - Buffer storing the whole source file contents |
|
774 @param aStart - Starting offset of the function name string |
|
775 @return true - If closing brace corresponding to function names is followed by semicolon |
|
776 @return false - If closing brace corresponding to function names is not by semicolon |
|
777 |
|
778 Following patterns are handled in this function: |
|
779 ----------------------------------------------- |
|
780 |
|
781 Pattern 1: NONSHARABLE_CLASS/NONSHARABLE_STRUCT modifier is used |
|
782 |
|
783 NONSHARABLE_CLASS(...) |
|
784 { |
|
785 |
|
786 }; |
|
787 |
|
788 Pattern 2: function definition is terminated by semicolon |
|
789 |
|
790 aaa(...) |
|
791 { |
|
792 |
|
793 } // comment |
|
794 ; |
|
795 |
|
796 Pattern 3: Class is defined in macro |
|
797 |
|
798 #define MACRO(arg) class name { }; |
|
799 |
|
800 */ |
|
801 |
|
802 bool TLeaveScanModel::CheckValidFuncName(const string &aFile, uint aStart) |
|
803 { |
|
804 bool returnValue=false; |
|
805 unsigned long uiNumberOfCurlyBraces = 1; |
|
806 unsigned int TempPosn = aStart; |
|
807 unsigned int open_brace = 0; |
|
808 unsigned int close_brace = 0; |
|
809 // Continue till than at least any of open curly or close curly brace is remaining |
|
810 while( !(open_brace == string::npos) || !(close_brace == string::npos) ) |
|
811 { |
|
812 open_brace = SmartFind(aFile, "{", TempPosn+1); |
|
813 close_brace = SmartFind(aFile, "}", TempPosn+1); |
|
814 |
|
815 if(open_brace < close_brace) // Handle which curly comes first |
|
816 { |
|
817 if((open_brace != string::npos)&& open_brace < aFile.size()) |
|
818 { |
|
819 uiNumberOfCurlyBraces++; // Update the curly counter |
|
820 TempPosn = open_brace; // move forward to the value from where the search of next curly to be started |
|
821 } |
|
822 } |
|
823 else // close brace comes first |
|
824 { |
|
825 if((close_brace != string::npos)&& close_brace < aFile.size()) |
|
826 { |
|
827 uiNumberOfCurlyBraces--; |
|
828 TempPosn = close_brace; // move forward to the value from where the search of next curly to be started |
|
829 } |
|
830 if(uiNumberOfCurlyBraces == 0) // Match to the corresponding close curly |
|
831 { |
|
832 break; |
|
833 } |
|
834 } |
|
835 } |
|
836 if(0 == uiNumberOfCurlyBraces) |
|
837 { |
|
838 string whiteSpaceChars = " \t\n\r"; |
|
839 unsigned int braceFollowsSemicolon1 = 0; |
|
840 unsigned int braceFollowsSemicolon2 = 0; |
|
841 |
|
842 braceFollowsSemicolon1 = SmartFind(aFile, ";", close_brace); // check if any semocolon exists after } |
|
843 braceFollowsSemicolon2 = aFile.find_first_not_of(whiteSpaceChars,close_brace+1); // Get the next character after close_brace |
|
844 |
|
845 if( (braceFollowsSemicolon1 == braceFollowsSemicolon2) && (braceFollowsSemicolon1 != string::npos) && (braceFollowsSemicolon2 != string::npos)) |
|
846 { |
|
847 returnValue = true; |
|
848 } |
|
849 } |
|
850 |
|
851 return returnValue; |
|
852 } |
|
853 /* |
|
854 This function checks whether the function name is specified with template class definition |
|
855 |
|
856 @internalComponent |
|
857 @released |
|
858 @param nstart - starting offset of the function name string |
|
859 @param nend - end offset of the function name string |
|
860 @return true - If function name is specified with template class functtion definition |
|
861 @return false - If function name is not specified with template class functtion definition |
|
862 |
|
863 Following patterns are handled in this function: |
|
864 ----------------------------------------------- |
|
865 |
|
866 Pattern 1: |
|
867 |
|
868 |
|
869 template <class T, class S, class L, class R> |
|
870 GLDEF_C void TestTDes<T,S,L,R>::Test1() |
|
871 { |
|
872 T a(_TL("ABc")); |
|
873 } |
|
874 */ |
|
875 |
|
876 bool TLeaveScanModel::CheckForTemplateFunc(const string& aFile,uint nstart,uint nend) |
|
877 { |
|
878 bool returnValue = false; |
|
879 uint OpennAnglebracket = aFile.find_first_of("<", nstart); // advance start |
|
880 if(nend == OpennAnglebracket ) // The first invalid char name is < |
|
881 { |
|
882 uint OpennParen = aFile.find_first_of("(", nstart); // advance start |
|
883 uint CloseAnglebracket = SmartFind(aFile, ">::", nstart ); |
|
884 if( (CloseAnglebracket < OpennParen) && (CloseAnglebracket > OpennAnglebracket)) |
|
885 { |
|
886 returnValue = true; |
|
887 } |
|
888 } |
|
889 return returnValue; |
|
890 } |
|
891 |
|
892 // Seek out mathod functions and return their name and start/end bounds in the |
|
893 // string file. |
|
894 // |
|
895 enum TReturnTypes TLeaveScanModel::GetFunc(const string& aFile, string &aName, uint &start, uint &end) |
|
896 { |
|
897 uint nstart = 0;//, cstart = 0; |
|
898 uint initStart = start; |
|
899 int realnstart = string::npos; |
|
900 uint safety = 1000000; |
|
901 string validNameChars = ":~abcdefghilkjmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890"; |
|
902 uint prevstart = string::npos; |
|
903 FOREVER// do // forever |
|
904 { |
|
905 if( |
|
906 (start == string::npos) || |
|
907 (prevstart == start && prevstart != string::npos) |
|
908 ) |
|
909 { |
|
910 return E_False; |
|
911 } |
|
912 prevstart = start; |
|
913 |
|
914 if (safety-- == 0) |
|
915 { |
|
916 cout << "ERROR: GetFunc context failure in " << iFileName << "\n"; |
|
917 exit(6); |
|
918 } |
|
919 |
|
920 // move start along to 'real' double-colon |
|
921 uint startColon = SmartFind(aFile, "::", start); |
|
922 uint parenPostn = SmartFind(aFile, "(", start + 1); |
|
923 |
|
924 if (startColon == string::npos || startColon >= aFile.length() ) |
|
925 { |
|
926 // Function Definition do not have any :: and function body contains |
|
927 nstart = start; |
|
928 // For 1st function, the value of start will be zero and for the |
|
929 // second function onwards, it will start after the first function ends |
|
930 } |
|
931 else |
|
932 { |
|
933 uint Realstartpost = GetRealStartPosition(aFile,parenPostn,0); |
|
934 // If no real function name exists after double colon |
|
935 // if (Realstartpost == 0) |
|
936 // return E_False; |
|
937 uint Realstartopnparen = SmartFind(aFile, "(", Realstartpost + 1); |
|
938 |
|
939 if(startColon < Realstartopnparen) |
|
940 { |
|
941 // If the double colon is used for function name then get function name which exists after :: |
|
942 nstart = startColon; |
|
943 //Get funcName before :: for "La :: La" |
|
944 //step1 ':: L...' |
|
945 uint fileLen = aFile.length(); |
|
946 int tmpnstart=nstart+2; |
|
947 bool step1 = false; |
|
948 while (tmpnstart<fileLen) |
|
949 { |
|
950 char curChar = aFile[tmpnstart]; |
|
951 if (curChar==' ' || curChar =='\n' || curChar=='\r' ||curChar=='\t') |
|
952 { |
|
953 tmpnstart++; |
|
954 } |
|
955 else if(curChar=='L') |
|
956 { |
|
957 step1=true; |
|
958 break; |
|
959 } |
|
960 else |
|
961 { |
|
962 step1 = false; |
|
963 break; |
|
964 } |
|
965 } |
|
966 if(step1) |
|
967 { |
|
968 //step2 L...(<>)? :: L... -->skip all the blank |
|
969 bool step2 = true; |
|
970 tmpnstart = nstart-1; |
|
971 while (tmpnstart>=0) |
|
972 { |
|
973 char curChar = aFile[tmpnstart]; |
|
974 if (curChar==' ' || curChar =='\n' || curChar=='\r' ||curChar=='\t') |
|
975 { |
|
976 tmpnstart--; |
|
977 } |
|
978 else |
|
979 { |
|
980 break; |
|
981 } |
|
982 } |
|
983 if(tmpnstart<=0) |
|
984 { |
|
985 tmpnstart = 0; |
|
986 step2 = false; |
|
987 } |
|
988 else |
|
989 { |
|
990 char curChar = aFile[tmpnstart]; |
|
991 if (curChar=='>') |
|
992 { |
|
993 tmpnstart = GetLeftTmpltParentBack(aFile,tmpnstart-1); |
|
994 if(tmpnstart==string::npos) |
|
995 { |
|
996 //bad pattern |
|
997 step2 =false; |
|
998 } |
|
999 else |
|
1000 { |
|
1001 tmpnstart --; |
|
1002 } |
|
1003 } |
|
1004 if(tmpnstart==string::npos) |
|
1005 { |
|
1006 //bad pattern |
|
1007 step2 =false; |
|
1008 } |
|
1009 else |
|
1010 { |
|
1011 |
|
1012 while (tmpnstart>=0) |
|
1013 { |
|
1014 curChar = aFile[tmpnstart]; |
|
1015 if (curChar==' ' || curChar =='\n' || curChar=='\r' ||curChar=='\t') |
|
1016 { |
|
1017 tmpnstart--; |
|
1018 } |
|
1019 else |
|
1020 { |
|
1021 break; |
|
1022 } |
|
1023 } |
|
1024 if(tmpnstart <=0) |
|
1025 { |
|
1026 tmpnstart=0; |
|
1027 step2=false; |
|
1028 } |
|
1029 while (tmpnstart>=0) |
|
1030 { |
|
1031 curChar = aFile[tmpnstart]; |
|
1032 if (curChar=='_' || (curChar>='a' && curChar<='z') || (curChar>='A' && curChar<='Z') ||(curChar>='0' && curChar<='9')) |
|
1033 { |
|
1034 tmpnstart--; |
|
1035 } |
|
1036 else |
|
1037 { |
|
1038 break; |
|
1039 } |
|
1040 } |
|
1041 tmpnstart++; |
|
1042 if (tmpnstart<0) |
|
1043 { |
|
1044 tmpnstart=0; |
|
1045 step2=false; |
|
1046 } |
|
1047 if ( step2 && aFile[tmpnstart]=='L') |
|
1048 { |
|
1049 realnstart = tmpnstart; |
|
1050 } |
|
1051 } |
|
1052 |
|
1053 } |
|
1054 } |
|
1055 } |
|
1056 else |
|
1057 { |
|
1058 // start looking for function name after '(' |
|
1059 nstart = aFile.find_last_of(validNameChars,parenPostn-1); |
|
1060 if(nstart == string::npos) |
|
1061 return E_False; |
|
1062 } |
|
1063 } |
|
1064 |
|
1065 uint semiPos = SmartFind(aFile, ";", nstart + 1); |
|
1066 |
|
1067 if (semiPos == string::npos || semiPos >= aFile.length()) |
|
1068 return E_False; |
|
1069 |
|
1070 uint parenPos = SmartFind(aFile, "(", nstart + 1); |
|
1071 if (parenPos == string::npos || parenPos >= aFile.length()) |
|
1072 return E_False; |
|
1073 |
|
1074 start = SmartFind(aFile, "{", nstart + 1); // advance start |
|
1075 if (start == string::npos || start >= aFile.length()) |
|
1076 return E_False; |
|
1077 |
|
1078 uint nstart2 = SmartFind(aFile, "::", nstart + 1); // next fn |
|
1079 // Either (1) Second instance of Double collon is not there and first occurrence of double colon is valid |
|
1080 // or (2) second occurrence of double colon is inside the function and first occurrence of double colon is valid |
|
1081 |
|
1082 if((nstart2 == string::npos && startColon < parenPos && startColon < start) || ( nstart2 > start && startColon < parenPos && startColon < start )) |
|
1083 { |
|
1084 // This variable will store the first paranthesis position in a temporary variable |
|
1085 // uint TempparenPos = parenPos; |
|
1086 uint Realstartpost = GetRealStartPosition(aFile,parenPos,1 /*To indicate that a valid double colon exists*/); |
|
1087 |
|
1088 nstart = Realstartpost+1; // reset |
|
1089 |
|
1090 break; |
|
1091 } |
|
1092 // Either Second occurrence of Double-colon is invalid |
|
1093 // or Second occurrence of Double-colon exists inside the function |
|
1094 // while first occurrence of double colon is valid |
|
1095 else if (nstart2 == string::npos || nstart2 >= aFile.length() || (nstart2 != string::npos && nstart2 > start && startColon < parenPos && startColon < start)) |
|
1096 { |
|
1097 // The opening parenthesis which comes fist after opening brace while moving |
|
1098 // in backward direction is a valid candidate for function name. |
|
1099 |
|
1100 // This variable will store the first paranthesis position |
|
1101 uint tempParenPos = aFile.find_last_of('(',start); |
|
1102 |
|
1103 |
|
1104 //void foo() throw () {;} |
|
1105 if(tempParenPos != string::npos) |
|
1106 { |
|
1107 uint throwPos = aFile.find("throw",initStart); |
|
1108 if(throwPos!=string::npos && throwPos>=initStart && throwPos<start) |
|
1109 { |
|
1110 tempParenPos = aFile.find_last_of('(',throwPos); |
|
1111 if(tempParenPos==string::npos || tempParenPos<initStart) |
|
1112 { |
|
1113 tempParenPos = aFile.find_last_of('(',throwPos); |
|
1114 } |
|
1115 } |
|
1116 } |
|
1117 |
|
1118 if (tempParenPos == string::npos) |
|
1119 { |
|
1120 //FIX this pattern |
|
1121 //class A{}; |
|
1122 //void foo(){fooL();} |
|
1123 if(start!=string::npos && semiPos!=string::npos && parenPos!=string::npos&&start<semiPos&&semiPos<parenPos) |
|
1124 { |
|
1125 start=semiPos+1; |
|
1126 return E_Continue; |
|
1127 } |
|
1128 //FIX this pattern |
|
1129 //class B; |
|
1130 //class B{}; |
|
1131 //void foo(){fooL();} |
|
1132 else if(start!=string::npos && semiPos!=string::npos && parenPos!=string::npos&&start<parenPos&&semiPos<start) |
|
1133 { |
|
1134 int tmpRightBracket = GetRightBracket(aFile,start+1); |
|
1135 int tmpNextLeftBracket = GetLeftBracket(aFile,tmpRightBracket); |
|
1136 int tmpSemiPos = aFile.find(";",tmpRightBracket); |
|
1137 if(tmpRightBracket!=string::npos&&tmpNextLeftBracket!=string::npos&&tmpSemiPos!=string::npos) |
|
1138 { |
|
1139 if(tmpRightBracket<tmpSemiPos && tmpSemiPos<tmpNextLeftBracket) |
|
1140 { |
|
1141 //skip the content before B{}; |
|
1142 start = tmpSemiPos; |
|
1143 return E_Continue; |
|
1144 } |
|
1145 } |
|
1146 } |
|
1147 //pattern: |
|
1148 //class temp |
|
1149 //{ |
|
1150 //LData func(); |
|
1151 //}; |
|
1152 //LData func() |
|
1153 //{ |
|
1154 // foo(); |
|
1155 //} |
|
1156 if(start!=string::npos && semiPos!=string::npos && parenPos!=string::npos&&start<semiPos&&semiPos>parenPos) |
|
1157 { |
|
1158 int tmpRightBracket = GetRightBracket(aFile,semiPos); |
|
1159 if(tmpRightBracket!=string::npos) |
|
1160 { |
|
1161 start = tmpRightBracket; |
|
1162 return E_Continue; |
|
1163 } |
|
1164 } |
|
1165 |
|
1166 // No '(' found yet |
|
1167 return E_False; |
|
1168 } |
|
1169 |
|
1170 |
|
1171 string whiteSpaceChars = " \t\n\r*&"; |
|
1172 |
|
1173 // ignore all tab and spaces and pointer between function name and opening parenthesis |
|
1174 uint nend = aFile.find_last_not_of(whiteSpaceChars, --tempParenPos); |
|
1175 uint currPos = aFile.find_last_of(whiteSpaceChars, nend); |
|
1176 |
|
1177 uint startOfBlock = SmartFind(aFile, "{", tempParenPos ); // advance start |
|
1178 |
|
1179 if (startOfBlock == string::npos || startOfBlock >= aFile.length()) |
|
1180 return E_False; |
|
1181 |
|
1182 if (start < tempParenPos || nstart2 < tempParenPos) |
|
1183 { |
|
1184 start = startOfBlock; |
|
1185 } |
|
1186 |
|
1187 if ((currPos != string::npos) && (currPos < tempParenPos)) // fn1 before fn2 |
|
1188 nstart = currPos+1; // reset |
|
1189 break; |
|
1190 } |
|
1191 |
|
1192 if (semiPos < start) // semi came before brace = prototype |
|
1193 start = semiPos; |
|
1194 else |
|
1195 if (nstart < nstart2 // fn1 before fn2 |
|
1196 && nstart2 < parenPos) // fn2 before paren |
|
1197 start = nstart2; // reset |
|
1198 else |
|
1199 break; |
|
1200 } //while (true); |
|
1201 |
|
1202 // nstart should be left pointing to first of double colons |
|
1203 // start should point to curly brace |
|
1204 |
|
1205 assert(aFile[start] == '{'); |
|
1206 |
|
1207 // locate the end of the method name |
|
1208 nstart = aFile.find_first_of(validNameChars,nstart); |
|
1209 if(nstart == string::npos) |
|
1210 return E_False; |
|
1211 |
|
1212 int nend = aFile.find_first_not_of(validNameChars, nstart); |
|
1213 if(true == CheckForTemplateFunc(aFile,nstart,nend)) |
|
1214 { |
|
1215 nend = aFile.find_first_of("(",nstart); |
|
1216 } |
|
1217 |
|
1218 if(realnstart!=string::npos && realnstart<nstart) |
|
1219 { |
|
1220 aName = aFile.substr(realnstart, nend - realnstart); |
|
1221 } |
|
1222 else |
|
1223 { |
|
1224 aName = aFile.substr(nstart, nend - nstart); |
|
1225 } |
|
1226 //operator |
|
1227 |
|
1228 if(aName.find("operator")!=string::npos) |
|
1229 { |
|
1230 nend = aFile.find_first_of("(",nstart); |
|
1231 while(nend>=0) |
|
1232 { |
|
1233 char tmpChar = aFile[nend]; |
|
1234 if(tmpChar == ' ' || tmpChar == '\n' ||tmpChar == '\t' ||tmpChar == 'r') |
|
1235 { |
|
1236 nend--; |
|
1237 } |
|
1238 else |
|
1239 { |
|
1240 break; |
|
1241 } |
|
1242 } |
|
1243 aName = aFile.substr(nstart, nend - nstart); |
|
1244 } |
|
1245 int typeEnd = aFile.find_last_of(validNameChars,nstart-1); |
|
1246 int typeStart= aFile.find_last_of(" \t\n\r*&",typeEnd)+1; |
|
1247 string type=TrimString(aFile.substr(typeStart, typeEnd - typeStart+1)); |
|
1248 uint closeparenposn = aFile.find_first_of(")", nstart); // advance start |
|
1249 |
|
1250 if( |
|
1251 (false == IsFunctionNameStringNotAMacro(aFile,start,closeparenposn,nstart)) || |
|
1252 (false == IsSemiColonAndAssignmentOccurs(aFile,start,closeparenposn)) |
|
1253 ) |
|
1254 { |
|
1255 |
|
1256 start = SmartFind(aFile, "}", start); |
|
1257 return E_Continue; |
|
1258 } |
|
1259 |
|
1260 // rewind nstart until non valid char found |
|
1261 safety = 1000000; |
|
1262 while (validNameChars.find_first_of(aFile[--nstart]) != string::npos) |
|
1263 { |
|
1264 if (safety-- == 0) |
|
1265 { |
|
1266 cout << "ERROR: GetFunc context failure in " << iFileName << "\n"; |
|
1267 exit(7); |
|
1268 } |
|
1269 } |
|
1270 |
|
1271 nstart++; // skip forward to acceptable character |
|
1272 |
|
1273 // cut name out |
|
1274 if(realnstart!=string::npos && realnstart<nstart) |
|
1275 { |
|
1276 aName = aFile.substr(realnstart, nend - realnstart); |
|
1277 } |
|
1278 else |
|
1279 { |
|
1280 aName = aFile.substr(nstart, nend - nstart); |
|
1281 } |
|
1282 |
|
1283 // truncate the name with zero |
|
1284 |
|
1285 if(realnstart!=string::npos && realnstart<nstart) |
|
1286 { |
|
1287 aName[nend-realnstart] = 0; |
|
1288 } |
|
1289 else |
|
1290 { |
|
1291 aName[nend-nstart] = 0; |
|
1292 } |
|
1293 aName = TrimString(aName); |
|
1294 uint NameSpaceinFunctionName = SmartFind(aName, "::",0); |
|
1295 // Continue processing when Either function name is in comment scope |
|
1296 // Or close curly corresponding to function name is followed by semicolon and pattern |
|
1297 // for scope resolution operator does not exists in function name |
|
1298 if(((true == IsInCommentScopeOrKeyword(aFile,aName,nstart,start))) || |
|
1299 ( (string::npos == NameSpaceinFunctionName) && ((true == CheckValidFuncName(aFile,start))))) |
|
1300 { |
|
1301 // Yes it is in comment scope |
|
1302 start = SmartFind(aFile, "}", start); |
|
1303 return E_Continue; |
|
1304 } |
|
1305 |
|
1306 if (Verbose) |
|
1307 cout << "Processing method " << iFileName << ": " << aName << "()\n"; |
|
1308 |
|
1309 end = start+1; // start was a curly brace, so place end inside the brace |
|
1310 int braceCount = 1; // count the one we've just stepped over & prime loop |
|
1311 //uint sanity = 0; |
|
1312 uint lpos = end; |
|
1313 uint match[E_Last]; |
|
1314 uint braceDepth = 1; |
|
1315 |
|
1316 // keep progressing 'end' until braces match, end finishes up at brace+1 |
|
1317 while (braceCount > 0) |
|
1318 { |
|
1319 if (Verbose > 1) |
|
1320 cout << "."; |
|
1321 |
|
1322 // reset all types (in case we don't use all of them) |
|
1323 int counter; |
|
1324 for (counter = E_LCleanedUp; counter < E_Last; counter++) |
|
1325 match[counter] = string::npos; |
|
1326 |
|
1327 match[E_OpenBrace] = aFile.find("{", lpos); |
|
1328 match[E_CloseBrace] = aFile.find("}", lpos); |
|
1329 match[E_BlockComment] = aFile.find("/*", lpos); |
|
1330 match[E_LineComment] = aFile.find("//", lpos); |
|
1331 match[E_String] = aFile.find("\"", lpos); |
|
1332 match[E_Quote] = aFile.find("\'", lpos); |
|
1333 |
|
1334 // Check for at least one match-type |
|
1335 bool nothingFound = true; |
|
1336 for(counter = E_LCleanedUp; counter < E_Last; counter++) |
|
1337 { |
|
1338 if(match[counter] != string::npos) // if found an item |
|
1339 nothingFound = false; |
|
1340 } |
|
1341 |
|
1342 if(nothingFound) |
|
1343 { |
|
1344 if (Verbose > 1) |
|
1345 cout << "\n"; |
|
1346 cout << "ERROR: " << iFileName << ":" << aName << " failed brace check.\n"; |
|
1347 exit(1); |
|
1348 } |
|
1349 |
|
1350 // Find the match-type which occurs first and set |
|
1351 // lps to its position |
|
1352 uint lowestMatchType = FindFirstMatchType(match); |
|
1353 lpos = match[lowestMatchType]; |
|
1354 |
|
1355 switch(lowestMatchType) |
|
1356 { |
|
1357 case E_BlockComment: |
|
1358 MoveToEndOfComment(aFile, lpos, string::npos); // lpos modified |
|
1359 break; |
|
1360 |
|
1361 case E_LineComment: |
|
1362 MoveToEndOfLine(aFile, lpos, string::npos); // lpos modified |
|
1363 break; |
|
1364 |
|
1365 case E_OpenBrace: |
|
1366 braceCount++; |
|
1367 if (braceCount > (int)braceDepth) |
|
1368 braceDepth = braceCount; |
|
1369 lpos++; |
|
1370 break; |
|
1371 |
|
1372 case E_CloseBrace: |
|
1373 braceCount--; |
|
1374 lpos++; |
|
1375 break; |
|
1376 |
|
1377 case E_String: |
|
1378 // we're sat on a quote, so advance |
|
1379 lpos++; |
|
1380 // Peek(file,lpos); |
|
1381 lpos = SmartFindEndOfString(aFile, lpos, '\"'); |
|
1382 if (lpos != string::npos) |
|
1383 lpos++; // skip closing quote |
|
1384 break; |
|
1385 |
|
1386 case E_Quote: |
|
1387 lpos++; |
|
1388 lpos = SmartFindEndOfString(aFile, lpos, '\''); |
|
1389 if (lpos != string::npos) |
|
1390 lpos++; // skip closing quote |
|
1391 break; |
|
1392 |
|
1393 default: |
|
1394 if (Verbose > 1) |
|
1395 cout << "\n"; |
|
1396 cout << "ERROR: " << iFileName << ":" << aName << " bad match type.\n"; |
|
1397 exit(1); |
|
1398 } //endsw |
|
1399 |
|
1400 if (lpos == string::npos || lpos == 0 || lpos > aFile.length()) |
|
1401 { |
|
1402 if (Verbose > 1) |
|
1403 cout << "\n"; |
|
1404 cout << "ERROR: " << iFileName << ":" << aName << " failed brace check (EOF).\n"; |
|
1405 exit(1); |
|
1406 } |
|
1407 |
|
1408 } //endwhile |
|
1409 |
|
1410 // advance 'end' |
|
1411 end = lpos; |
|
1412 |
|
1413 if (braceDepth > 10) |
|
1414 { |
|
1415 if (Verbose > 1) |
|
1416 cout << "\n"; |
|
1417 cout << "WARNING: " << iFileName << ":" << aName << " unexpectedly large brace depth.\n"; |
|
1418 } |
|
1419 return E_True; |
|
1420 } |
|
1421 |
|
1422 // Diagnostic function for displaying the contents of a string |
|
1423 // starting at 'pos' |
|
1424 // |
|
1425 void TLeaveScanModel::Peek(const string aStr, uint aPos) |
|
1426 { |
|
1427 #define PEEKBUFFSIZE 20 |
|
1428 static char peekBuf[PEEKBUFFSIZE]; |
|
1429 int posn = aPos; |
|
1430 int remaining = aStr.length() - posn; |
|
1431 |
|
1432 if (remaining > (PEEKBUFFSIZE - 1)) |
|
1433 remaining = PEEKBUFFSIZE; |
|
1434 |
|
1435 for (int i = 0; i < remaining; i++) |
|
1436 peekBuf[i] = aStr[i+posn]; |
|
1437 |
|
1438 peekBuf[remaining] = 0; |
|
1439 |
|
1440 cout << "-------- Peek -----------\n" << peekBuf << "\n"; |
|
1441 cout << "-------------------------\n"; |
|
1442 #undef PEEKBUFFSIZE |
|
1443 } |
|
1444 |
|
1445 // Given an array of match types, work out which one actually comes first |
|
1446 // in the string. Effectively this function returns the match type with the |
|
1447 // lowest 'pos' value. |
|
1448 // |
|
1449 uint TLeaveScanModel::FindFirstMatchType(uint aMatchSet[]) |
|
1450 { |
|
1451 // load indexOfLowestMatch with the item which comes first in the fn |
|
1452 int lowestMatch = 0; |
|
1453 for(int i = E_LCleanedUp; i < E_Last; i++) |
|
1454 { |
|
1455 if((aMatchSet[lowestMatch] == string::npos) // if didn't find one |
|
1456 ||(aMatchSet[lowestMatch] > aMatchSet[i] && aMatchSet[i] != string::npos)) |
|
1457 lowestMatch = i; |
|
1458 } |
|
1459 // cout << "Lowest match found: " << (int)lowestMatch << "\n"; |
|
1460 return lowestMatch; |
|
1461 } |
|
1462 |
|
1463 // |
|
1464 // Given a string, see if it looks like a macro (e.g. is capitalised) |
|
1465 // |
|
1466 bool TLeaveScanModel::IdentifyMacro(const string& str, const uint aPos) |
|
1467 { |
|
1468 string validNameChars = ":~abcdefghilkjmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890"; |
|
1469 string LowerNameChars = "abcdefghilkjmnopqrstuvwxyz"; |
|
1470 |
|
1471 // backwind until not valid |
|
1472 int start = str.find_last_not_of(validNameChars, aPos); |
|
1473 |
|
1474 // check for any lower case between start and pos |
|
1475 int lower = str.find_first_of(LowerNameChars, start); |
|
1476 |
|
1477 bool result = false; |
|
1478 if (lower < (int)aPos) |
|
1479 result = false; // lower case == not macro |
|
1480 else |
|
1481 result = true; |
|
1482 return result; |
|
1483 } |
|
1484 |
|
1485 // Given a method function bound, search thorough it looking for what appear to be |
|
1486 // leaving functions (unless it's a leaver itself). |
|
1487 // |
|
1488 // Returns false if error was detected signifying that caller should dump the |
|
1489 // error string. |
|
1490 // |
|
1491 bool TLeaveScanModel::CheckFunc(const string& aFile, string &aName, |
|
1492 uint start, uint end, bool& aIsLeaver) |
|
1493 { |
|
1494 // entry criteria: name points to the container function name (after double-colon) which |
|
1495 // is now null-terminated. |
|
1496 // end is the bound for the end of the function (closing curly brace) |
|
1497 string extraTypes="CDX"; |
|
1498 // Look for container name ending in L, or LC, LD, or LX |
|
1499 bool isLCFunc =false; |
|
1500 aName = TrimString(aName); |
|
1501 |
|
1502 string className=""; |
|
1503 className = GetClassName( start); |
|
1504 if(className!="") |
|
1505 { |
|
1506 aName = className+"::"+aName; |
|
1507 } |
|
1508 |
|
1509 if (Verbose > 1) |
|
1510 { |
|
1511 cout << "Evaluating code:\n"; |
|
1512 Peek(aFile, start); |
|
1513 } |
|
1514 |
|
1515 if (aName[aName.length()-1] == 'L' || |
|
1516 (aName[aName.length()-2] == 'L' && string::npos != extraTypes.find(aName[aName.length()-1]) ) ) |
|
1517 //return true; // happy - we can exit since this container is marked as a leaver |
|
1518 aIsLeaver = true; // container is marked Leaver - used to return here |
|
1519 else if(IsLClassCtor(aName)) |
|
1520 { |
|
1521 aIsLeaver = true; |
|
1522 } |
|
1523 |
|
1524 else |
|
1525 aIsLeaver = false; // container not marked Leaver |
|
1526 |
|
1527 if (aName[aName.length()-1] == 'C' && aName[aName.length()-2] == 'L' ) |
|
1528 { |
|
1529 isLCFunc =true; |
|
1530 } |
|
1531 //CheckFuncDecl |
|
1532 //CheckFuncParam |
|
1533 int classNamePos = aFile.rfind(aName, start); |
|
1534 if(classNamePos == string::npos) |
|
1535 { |
|
1536 uint coloncolonPos = aName.find("::"); |
|
1537 if(coloncolonPos != string::npos) |
|
1538 { |
|
1539 string shortFuncName = aName.substr(coloncolonPos+2); |
|
1540 classNamePos = aFile.rfind(shortFuncName,start); |
|
1541 } |
|
1542 } |
|
1543 string funcParam = GetFunctionParam(aFile, classNamePos-1); |
|
1544 if(funcParam != "") |
|
1545 { |
|
1546 if(funcParam.find("LString")!=string::npos||(funcParam.find("LData")!=string::npos)) |
|
1547 { |
|
1548 if(!aIsLeaver) |
|
1549 { |
|
1550 cout<<GetErrorLineHead(aFile,classNamePos)<<aName + " uses LString/LData class as parameter"<<endl; |
|
1551 } |
|
1552 } |
|
1553 } |
|
1554 //CheckFuncHead |
|
1555 string funcHead = GetFunctionHead(aFile, classNamePos-1); |
|
1556 if(funcHead != "") |
|
1557 { |
|
1558 if(funcHead.find("LString")!=string::npos||(funcHead.find("LData")!=string::npos)) |
|
1559 { |
|
1560 if(!aIsLeaver) |
|
1561 { |
|
1562 cout<<GetErrorLineHead(aFile,classNamePos)<<aName + " returns LString/LData class"<<endl; |
|
1563 } |
|
1564 } |
|
1565 } |
|
1566 // remainder of function exists to deal with non-leaving container |
|
1567 bool ok = true; |
|
1568 uint bodyLen = end - start; |
|
1569 iBody = aFile.substr(start, bodyLen); // bound the string to end |
|
1570 |
|
1571 uint lpos = 0; |
|
1572 uint match[E_Last]; // create some search-result slots |
|
1573 string extraTypesAndSpace=" CDX"; |
|
1574 |
|
1575 bool keepProcessing = true; // keep going unless we run out of data or bail |
|
1576 uint sanity = 1000000; |
|
1577 |
|
1578 while (lpos < bodyLen && keepProcessing == true) |
|
1579 { |
|
1580 if (sanity-- == 0) |
|
1581 { |
|
1582 cout << "\nERROR: " << iFileName << ": " << aName << " context failure.\n"; |
|
1583 exit(4); |
|
1584 } |
|
1585 if (Verbose > 1) |
|
1586 cout << "?"; |
|
1587 // Scans for a whole set of items from position lpos. |
|
1588 // string::npos returned if not found |
|
1589 |
|
1590 // reset all types (in case we don't use all of them) |
|
1591 int counter; |
|
1592 for (counter = E_LCleanedUp; counter < E_Last; counter++) |
|
1593 match[counter] = string::npos; |
|
1594 |
|
1595 match[E_Ell] = iBody.find("L", lpos); |
|
1596 match[E_Trap] = iBody.find("TRAP", lpos); |
|
1597 match[E_BlockComment] = iBody.find("/*", lpos); |
|
1598 match[E_LineComment] = iBody.find("//", lpos); |
|
1599 match[E_Eleave] = iBody.find("ELeave", lpos); |
|
1600 match[E_UserEleave] = iBody.find("User::Leave", lpos); |
|
1601 match[E_String] = iBody.find("\"", lpos); |
|
1602 match[E_Quote] = iBody.find("\'", lpos); |
|
1603 match[E_OrLeave] = iBody.find("OR_LEAVE", lpos); |
|
1604 match[E_LCleanedUp] = iBody.find("LCleanedup", lpos); |
|
1605 match[E_LString] = iBody.find("LString", lpos); |
|
1606 match[E_LManaged] = iBody.find("LManaged", lpos); |
|
1607 match[E_LData] = iBody.find("LData", lpos); |
|
1608 |
|
1609 // Check for at least one match-type |
|
1610 bool doBreak = true; |
|
1611 for(counter = E_LCleanedUp; counter < E_Last; counter++) |
|
1612 { |
|
1613 if(match[counter] != string::npos) // if found an item |
|
1614 doBreak = false; |
|
1615 } |
|
1616 |
|
1617 if(doBreak) |
|
1618 break; // found nothing of interest in this method function |
|
1619 |
|
1620 // Find the match-type which occurs first and set |
|
1621 // lps to its position |
|
1622 uint lowestMatchType = FindFirstMatchType(match); |
|
1623 lpos = match[lowestMatchType]; |
|
1624 |
|
1625 switch(lowestMatchType) // what type was it? |
|
1626 { |
|
1627 case E_BlockComment: |
|
1628 MoveToEndOfComment(iBody, lpos, bodyLen); // lpos modified |
|
1629 break; |
|
1630 |
|
1631 case E_LineComment: |
|
1632 MoveToEndOfLine(iBody, lpos, bodyLen); // lpos modified |
|
1633 break; |
|
1634 |
|
1635 case E_Trap: |
|
1636 if (! MoveToEndOfTrapHarness(iBody, lpos, bodyLen)) // lpos modified |
|
1637 { |
|
1638 iErrorString = aName + " structure Fault-Unclosed bracket after TRAP harness."; |
|
1639 iPositionOfError = lpos; |
|
1640 keepProcessing = false; // bail |
|
1641 } |
|
1642 break; |
|
1643 |
|
1644 case E_Eleave: |
|
1645 ok = false; |
|
1646 iErrorString = aName + " calls new(ELeave)."; |
|
1647 iPositionOfError = match[E_Eleave]; |
|
1648 keepProcessing = false; // bail |
|
1649 break; |
|
1650 case E_OrLeave: |
|
1651 ok = false; |
|
1652 iErrorString = aName + " calls OR_LEAVE."; |
|
1653 iPositionOfError = match[E_OrLeave]; |
|
1654 keepProcessing = false; // bail |
|
1655 break; |
|
1656 case E_LCleanedUp: |
|
1657 ok = false; |
|
1658 iErrorString = aName + " uses LCleanedup* class."; |
|
1659 iPositionOfError = match[E_LCleanedUp]; |
|
1660 keepProcessing = false; // bail |
|
1661 break; |
|
1662 case E_LString: |
|
1663 ok = false; |
|
1664 iErrorString = aName + " uses LString* class."; |
|
1665 iPositionOfError = match[E_LString]; |
|
1666 keepProcessing = false; // bail |
|
1667 break; |
|
1668 case E_LManaged: |
|
1669 ok = false; |
|
1670 iErrorString = aName + " uses LManaged* class."; |
|
1671 iPositionOfError = match[E_LManaged]; |
|
1672 keepProcessing = false; // bail |
|
1673 break; |
|
1674 |
|
1675 case E_LData: |
|
1676 ok = false; |
|
1677 iErrorString = aName + " uses LData* class."; |
|
1678 iPositionOfError = match[E_LData]; |
|
1679 keepProcessing = false; // bail |
|
1680 break; |
|
1681 |
|
1682 case E_UserEleave: |
|
1683 ok = false; |
|
1684 iErrorString = aName + " calls User::Leave() or User::LeaveIfError()."; |
|
1685 iPositionOfError = match[E_UserEleave]; |
|
1686 AppendCommentToErrorString(bodyLen); |
|
1687 keepProcessing = false; // bail |
|
1688 break; |
|
1689 |
|
1690 |
|
1691 case E_Ell: |
|
1692 // Found an L, but is there an underbar before it, |
|
1693 // AND (one of 'CDX ' AND a brace OR just a brace) _L[CDX ]( |
|
1694 if ((iBody[lpos - 1] != '_') && |
|
1695 (((string::npos != extraTypesAndSpace.find(iBody[lpos + 1])) |
|
1696 && (iBody[lpos + 2] == '(')) || (iBody[lpos + 1] == '(')) ) |
|
1697 { |
|
1698 if (IdentifyMacro(iBody, lpos)) |
|
1699 { |
|
1700 ok = false; |
|
1701 iErrorString = aName + " may employ a macro."; |
|
1702 iPositionOfError = match[E_Ell]; |
|
1703 if(!AppendCommentToErrorString(bodyLen)) |
|
1704 keepProcessing = false; // keep going if possible |
|
1705 lpos++; |
|
1706 break; // don't bail - false alarm |
|
1707 } |
|
1708 else |
|
1709 { |
|
1710 if (Verbose > 1) |
|
1711 { |
|
1712 cout << "Leaver found: \n"; |
|
1713 Peek(iBody, lpos); |
|
1714 } |
|
1715 } |
|
1716 ok = false; |
|
1717 iErrorString = aName + " calls a function that can leave."; |
|
1718 iPositionOfError = match[E_Ell]; |
|
1719 if(!AppendCommentToErrorString(bodyLen)) |
|
1720 keepProcessing = false; // keep going if possible |
|
1721 } |
|
1722 lpos++; // move on over the L |
|
1723 break; |
|
1724 |
|
1725 case E_String: |
|
1726 lpos++; |
|
1727 lpos = SmartFindEndOfString(iBody, lpos, '\"'); |
|
1728 if (lpos == string::npos) |
|
1729 keepProcessing = false; |
|
1730 else |
|
1731 lpos++; // skip closing quote |
|
1732 break; |
|
1733 |
|
1734 case E_Quote: |
|
1735 lpos++; |
|
1736 lpos = SmartFindEndOfString(iBody, lpos, '\''); |
|
1737 if (lpos == string::npos) |
|
1738 keepProcessing = false; |
|
1739 else |
|
1740 lpos++; // skip closing quote |
|
1741 break; |
|
1742 |
|
1743 default: |
|
1744 cout << "\nERROR: " << iFileName << ": " << aName << " unexpected match type.\n"; |
|
1745 exit(1); |
|
1746 |
|
1747 } // endsw |
|
1748 //LCleanedup and LManaged cann't be TRAPed |
|
1749 /* |
|
1750 if (match[E_LCleanedUp]==string::npos && match[E_LManaged]==string::npos) |
|
1751 { |
|
1752 } |
|
1753 if(match[E_LCleanedUp]!=string::npos && match[E_LManaged]==string::npos) |
|
1754 { |
|
1755 ok = false; |
|
1756 iErrorString = aName + " uses LCleanedup class."; |
|
1757 iPositionOfError = match[E_LCleanedUp]; |
|
1758 keepProcessing = false; // bail |
|
1759 break; |
|
1760 } |
|
1761 else if(match[E_LManaged]!=string::npos && match[E_LCleanedUp]==string::npos) |
|
1762 { |
|
1763 ok = false; |
|
1764 iErrorString = aName + " uses LManaged* class."; |
|
1765 iPositionOfError = match[E_LManaged]; |
|
1766 keepProcessing = false; // bail |
|
1767 break; |
|
1768 } |
|
1769 else if(match[E_LCleanedUp]<match[E_LManaged]) |
|
1770 { |
|
1771 ok = false; |
|
1772 iErrorString = aName + " uses LCleanedup class."; |
|
1773 iPositionOfError = match[E_LCleanedUp]; |
|
1774 keepProcessing = false; // bail |
|
1775 break; |
|
1776 } |
|
1777 else if(match[E_LCleanedUp]>match[E_LManaged]) |
|
1778 { |
|
1779 ok = false; |
|
1780 iErrorString = aName + " uses LManaged* class."; |
|
1781 iPositionOfError = match[E_LManaged]; |
|
1782 keepProcessing = false; // bail |
|
1783 break; |
|
1784 } |
|
1785 */ |
|
1786 //check:An LCleanedup class is used in the same function body as the Classic cleanup stack API |
|
1787 if(match[E_LCleanedUp]!=string::npos) |
|
1788 { |
|
1789 uint newLCPos = iBody.find("NewLC"); |
|
1790 uint pushLPos = string::npos; //Cleanedup::PushL()-->find Cleanedup |
|
1791 uint bodyLen = iBody.length(); |
|
1792 for(uint tmpPos = 0;tmpPos<bodyLen;) |
|
1793 { |
|
1794 pushLPos = iBody.find("CleanupStack",tmpPos); |
|
1795 if (pushLPos == string::npos) |
|
1796 { |
|
1797 break; |
|
1798 } |
|
1799 if(pushLPos>0) |
|
1800 { |
|
1801 if(iBody[pushLPos-1]=='L') |
|
1802 { |
|
1803 tmpPos++; |
|
1804 pushLPos = string::npos; |
|
1805 continue; |
|
1806 } |
|
1807 else |
|
1808 { |
|
1809 break; |
|
1810 } |
|
1811 } |
|
1812 else |
|
1813 { |
|
1814 break; |
|
1815 } |
|
1816 } |
|
1817 |
|
1818 //uint new |
|
1819 uint lcleanedUpPos = match[E_LCleanedUp]; |
|
1820 if(newLCPos!=string::npos && pushLPos!=string::npos) |
|
1821 { |
|
1822 if(newLCPos<pushLPos) |
|
1823 { |
|
1824 cout<<GetErrorLineHead(aFile,start+newLCPos)<<aName<<" uses NewLC method with LCleanedup* class.\n"; |
|
1825 break; |
|
1826 } |
|
1827 else |
|
1828 { |
|
1829 cout<<GetErrorLineHead(aFile,start+pushLPos)<<aName<<" uses classic CleanupStack method with LCleanedup* class.\n"; |
|
1830 break; |
|
1831 } |
|
1832 } |
|
1833 else if(newLCPos!=string::npos) |
|
1834 { |
|
1835 cout<<GetErrorLineHead(aFile,start+newLCPos)<<aName<<" uses NewLC method with LCleanedup* class.\n"; |
|
1836 break; |
|
1837 } |
|
1838 else if(pushLPos!=string::npos) |
|
1839 { |
|
1840 cout<<GetErrorLineHead(aFile,start+pushLPos)<<aName<<" uses classic CleanupStack with LCleanedup* class.\n"; |
|
1841 break; |
|
1842 } |
|
1843 |
|
1844 } |
|
1845 } // endwhile |
|
1846 |
|
1847 if (Verbose > 1) |
|
1848 cout << "END\n"; |
|
1849 |
|
1850 return ok; |
|
1851 } |
|
1852 |
|
1853 // |
|
1854 // Move an index forward to the start of a close-comment |
|
1855 // |
|
1856 void TLeaveScanModel::MoveToEndOfComment(const string& aStr, uint& aIndex, uint aLen) |
|
1857 { |
|
1858 uint endOfComment=aStr.find("*/",aIndex); |
|
1859 aIndex=(endOfComment == string::npos ? aLen : endOfComment+2); |
|
1860 } |
|
1861 |
|
1862 // |
|
1863 // Move an index forward to the EOL (\n) |
|
1864 // |
|
1865 void TLeaveScanModel::MoveToEndOfLine(const string& aStr, uint& aIndex, uint aLen) |
|
1866 { |
|
1867 uint endOfLine=aStr.find('\n',aIndex); |
|
1868 aIndex=(endOfLine==string::npos ? aLen : endOfLine); |
|
1869 } |
|
1870 |
|
1871 // |
|
1872 // Move an index forward to a closing quote (specified by x) |
|
1873 // |
|
1874 void TLeaveScanModel::MoveToEndOfString(const string& aStr, uint& aIndex, uint aLen, char aQuote) |
|
1875 { |
|
1876 uint endOfLine=aStr.find(aQuote,aIndex); |
|
1877 aIndex=(endOfLine==string::npos ? aLen : endOfLine); |
|
1878 } |
|
1879 |
|
1880 // |
|
1881 // Move to end of a trap harness |
|
1882 // |
|
1883 bool TLeaveScanModel::MoveToEndOfTrapHarness(const string& aStr, uint& aIndex, uint aLen) |
|
1884 { |
|
1885 uint bracketLevel=1; |
|
1886 uint closeBracket; |
|
1887 uint openBracket=aStr.find('(',aIndex); |
|
1888 bool cleanExit=true; |
|
1889 uint newIndex; |
|
1890 for(newIndex = openBracket; bracketLevel;) |
|
1891 { |
|
1892 closeBracket=aStr.find(')',newIndex+1); |
|
1893 openBracket=aStr.find('(',newIndex+1); |
|
1894 if (openBracket<closeBracket && openBracket!=string::npos) |
|
1895 { |
|
1896 bracketLevel++; |
|
1897 newIndex=openBracket; |
|
1898 } |
|
1899 else if ((closeBracket<openBracket && closeBracket!=string::npos) |
|
1900 || (closeBracket!=string::npos && openBracket==string::npos)) |
|
1901 { |
|
1902 bracketLevel--; |
|
1903 newIndex=closeBracket; |
|
1904 } |
|
1905 else //bad structure |
|
1906 { |
|
1907 cleanExit=false; |
|
1908 break; |
|
1909 } |
|
1910 } |
|
1911 aIndex=(cleanExit ? newIndex : aLen); |
|
1912 return cleanExit; |
|
1913 } |
|
1914 |
|
1915 // |
|
1916 // Report the current error - note works on class member iText |
|
1917 // |
|
1918 void TLeaveScanModel::ReportErrorLineAndString(uint aStart) |
|
1919 { |
|
1920 int positionInBody=aStart+iPositionOfError; |
|
1921 int positionOfNextLine=iText.find('\n',positionInBody+1); |
|
1922 if(positionOfNextLine==string::npos) |
|
1923 positionOfNextLine=iText.length()-1; //the first char could be '\n' |
|
1924 int positionOfLine=-1; |
|
1925 int lineNum; |
|
1926 for(lineNum=0 ;positionOfLine<positionOfNextLine;lineNum++) |
|
1927 positionOfLine=iText.find('\n',positionOfLine+1); |
|
1928 |
|
1929 cout << iFileName <<"("<< lineNum << ") : " << iErrorString << "\n"; |
|
1930 } |
|
1931 |
|
1932 //calculate filename ,fileline |
|
1933 string TLeaveScanModel::GetErrorLineHead(const string& aText, uint aPos) |
|
1934 { |
|
1935 int lineNum=1; |
|
1936 char curChar=0; |
|
1937 //i did not count '\r' |
|
1938 for(int curPos=0;curPos<=aPos;curPos++) |
|
1939 { |
|
1940 curChar = aText[curPos]; |
|
1941 if(curChar=='\n') |
|
1942 { |
|
1943 lineNum++; |
|
1944 } |
|
1945 } |
|
1946 stringstream sstrm; |
|
1947 sstrm<<iFileName << string("(")<<lineNum<<string(") : "); |
|
1948 return sstrm.str(); |
|
1949 } |
|
1950 //Get a class name from class list |
|
1951 //may return wrong name if there are inner classes |
|
1952 string TLeaveScanModel::GetClassName(uint aStart) |
|
1953 { |
|
1954 list<ClassMeta>::iterator iter; |
|
1955 for(iter=iClassList.begin();iter!=iClassList.end();iter++) |
|
1956 { |
|
1957 if(iter->startPos<=aStart && iter->endPos >= aStart) |
|
1958 { |
|
1959 return iter->className; |
|
1960 } |
|
1961 } |
|
1962 return ""; |
|
1963 } |
|
1964 // |
|
1965 // Add to the current error string - note works on class member iBody |
|
1966 // |
|
1967 bool TLeaveScanModel::AppendCommentToErrorString(uint aEnd) |
|
1968 { |
|
1969 bool qualified = true; |
|
1970 uint commentPosition = iBody.find("//",iPositionOfError+1); |
|
1971 uint endOfLinePosition = iBody.find('\n',iPositionOfError+1); |
|
1972 if((commentPosition < endOfLinePosition) && (commentPosition != string::npos)) |
|
1973 iErrorString+=" QUALIFIED WITH-> "+iBody.substr(commentPosition,endOfLinePosition-commentPosition); |
|
1974 else if(endOfLinePosition==string::npos && commentPosition!=string::npos) |
|
1975 iErrorString+=" QUALIFIED WITH-> "+iBody.substr(commentPosition,aEnd-commentPosition); |
|
1976 else //no comment |
|
1977 { |
|
1978 iErrorString+=" UnQualified."; |
|
1979 qualified = false; |
|
1980 } |
|
1981 return qualified; |
|
1982 } |
|
1983 |
|
1984 // |
|
1985 // Find the end of a string, but cope with escaped quotes |
|
1986 // |
|
1987 uint TLeaveScanModel::SmartFindEndOfString(const string& aStr, uint aPos, char aQuote) |
|
1988 { |
|
1989 FOREVER//while(true) |
|
1990 { |
|
1991 MoveToEndOfString(aStr, aPos, string::npos, aQuote); |
|
1992 if (aPos == string::npos) // end of fn |
|
1993 return aPos; |
|
1994 |
|
1995 if (aStr[aPos - 1] != '\\') |
|
1996 return aPos; |
|
1997 |
|
1998 // looks like we have an escaped quote |
|
1999 if (aStr[aPos - 2] == '\\') |
|
2000 { // escape was itself quoted, so string end is real |
|
2001 return aPos; |
|
2002 } |
|
2003 else |
|
2004 { // quote is escaped - carry on |
|
2005 if (Verbose > 1) |
|
2006 cout << "\n"; |
|
2007 cout << "WARNING: " << iFileName << ": detected quoted string.\n"; |
|
2008 aPos++; |
|
2009 continue; |
|
2010 } |
|
2011 } //while |
|
2012 } |
|
2013 |
|
2014 // |
|
2015 // Find a target string from a given start position, but ignore targets buried |
|
2016 // within comments, or strings. |
|
2017 // |
|
2018 uint TLeaveScanModel::SmartFind(const string& aStr, const string& aTarget, uint aStart) |
|
2019 { |
|
2020 uint found,cstart; |
|
2021 FOREVER//while(1) |
|
2022 { |
|
2023 // cout << "Searching for target from: " << aStart << "\n"; |
|
2024 // record found target |
|
2025 found = aStr.find(aTarget, aStart); |
|
2026 if (found == string::npos) |
|
2027 return(string::npos); |
|
2028 |
|
2029 // cout << "Target candidate found at: " << found << "\n"; |
|
2030 // look for earlier comment |
|
2031 cstart = aStr.find("//", aStart); |
|
2032 |
|
2033 if (cstart < found) // earlier |
|
2034 { |
|
2035 aStart = cstart; // reset start to after comment |
|
2036 // cout << "Earlier comment found at: " << start << "\n"; |
|
2037 MoveToEndOfLine(aStr, aStart, string::npos); |
|
2038 // cout << "Start advanced to: " << aStart << "\n"; |
|
2039 if (aStart == string::npos) |
|
2040 return(aStart); |
|
2041 else |
|
2042 continue; // start search again |
|
2043 } |
|
2044 |
|
2045 // do the same for block comments |
|
2046 cstart = aStr.find("/*", aStart); |
|
2047 if (cstart < found) |
|
2048 { |
|
2049 aStart = cstart; |
|
2050 // cout << "Earlier block found at: " << aStart << "\n"; |
|
2051 MoveToEndOfComment(aStr, aStart, string::npos); |
|
2052 // cout << "Start advanced to: " << aStart << "\n"; |
|
2053 if (aStart == string::npos) |
|
2054 return(aStart); |
|
2055 else |
|
2056 continue; |
|
2057 } |
|
2058 |
|
2059 cstart = aStr.find("\"", aStart); |
|
2060 |
|
2061 if (cstart < found) |
|
2062 { |
|
2063 aStart = cstart + 1; |
|
2064 MoveToEndOfString(aStr, aStart, string::npos, '\"'); |
|
2065 if (aStart == string::npos) |
|
2066 return(aStart); |
|
2067 else |
|
2068 { |
|
2069 aStart++; |
|
2070 continue; |
|
2071 } |
|
2072 } |
|
2073 |
|
2074 cstart = aStr.find("\'", aStart); |
|
2075 if (cstart < found) |
|
2076 { |
|
2077 aStart = cstart + 1; |
|
2078 MoveToEndOfString(aStr, aStart, string::npos, '\''); |
|
2079 if (aStart == string::npos) |
|
2080 return(aStart); |
|
2081 else |
|
2082 { |
|
2083 aStart++; |
|
2084 continue; |
|
2085 } |
|
2086 } |
|
2087 return(found); // quit loop |
|
2088 } // endwhile |
|
2089 } |
|
2090 |
|
2091 |
|
2092 /* |
|
2093 * Decide the "class" is keyword |
|
2094 * e.g |
|
2095 * class -> true |
|
2096 * Aclass ->false |
|
2097 * classA ->false |
|
2098 */ |
|
2099 bool TLeaveScanModel::IsClassKeyword(const string& aText, uint aBegin, uint aEnd) |
|
2100 { |
|
2101 bool tmpBefore =false; |
|
2102 bool tmpAfter =false; |
|
2103 int len = aText.size(); |
|
2104 if(aBegin==0) |
|
2105 { |
|
2106 tmpBefore = true; |
|
2107 } |
|
2108 else |
|
2109 { |
|
2110 char tmpChar = aText[aBegin-1]; |
|
2111 if(tmpChar==' ' || tmpChar=='\n' || tmpChar=='\r' || tmpChar=='\t' || tmpChar=='{'|| tmpChar=='}'|| tmpChar==';') |
|
2112 { |
|
2113 tmpBefore = true; |
|
2114 } |
|
2115 } |
|
2116 if(aEnd==len-1) |
|
2117 { |
|
2118 tmpAfter = true; |
|
2119 } |
|
2120 else |
|
2121 { |
|
2122 char tmpChar = aText[aEnd+1]; |
|
2123 if(tmpChar==' ' || tmpChar=='\n' || tmpChar=='\r' || tmpChar=='{' || tmpChar=='('|| tmpChar==':') |
|
2124 { |
|
2125 tmpAfter = true; |
|
2126 } |
|
2127 } |
|
2128 return tmpAfter&&tmpBefore; |
|
2129 } |
|
2130 /** |
|
2131 * combine escaped lines to one line. |
|
2132 */ |
|
2133 string TLeaveScanModel::CombineLine(const string& aText) |
|
2134 { |
|
2135 |
|
2136 if(aText.size()<0) return string(""); |
|
2137 int curPos = 0; |
|
2138 int curState = PPSTATE_NORMAL; |
|
2139 int firstPos = 0; |
|
2140 int stringSize = aText.size(); |
|
2141 int newlineCount=0; |
|
2142 string newText(""); |
|
2143 while(curPos< stringSize) |
|
2144 { |
|
2145 //remove "\" |
|
2146 switch(curState) |
|
2147 { |
|
2148 case PPSTATE_NORMAL: |
|
2149 { |
|
2150 char curChar=aText[curPos]; |
|
2151 if(curChar=='\\') |
|
2152 { |
|
2153 // '\\\n" | "\\\r" |
|
2154 if(stringSize>(curPos+1)&&IsNewLine(aText[curPos+1])) |
|
2155 { |
|
2156 curState= PPSTATE_ESCAPED_LINE; |
|
2157 newText.append(aText.substr(firstPos,curPos-firstPos)); |
|
2158 curPos+=1; |
|
2159 newlineCount+=1; |
|
2160 |
|
2161 } |
|
2162 else if(IsLastChar(curPos,stringSize)) |
|
2163 { |
|
2164 curPos++; |
|
2165 firstPos++; |
|
2166 } |
|
2167 else |
|
2168 { |
|
2169 curPos++; |
|
2170 } |
|
2171 } |
|
2172 else if(IsNewLine(curChar)) |
|
2173 { |
|
2174 if (newlineCount>0) |
|
2175 { |
|
2176 newText.append(aText.substr(firstPos,curPos-firstPos)); |
|
2177 while(newlineCount>= 0) |
|
2178 { |
|
2179 newText.append("\n"); |
|
2180 newlineCount--; |
|
2181 } |
|
2182 newlineCount=0; |
|
2183 curPos++; |
|
2184 firstPos=curPos; |
|
2185 } |
|
2186 else |
|
2187 { |
|
2188 curPos++; |
|
2189 } |
|
2190 } |
|
2191 else |
|
2192 { |
|
2193 curPos++; |
|
2194 } |
|
2195 } |
|
2196 break; |
|
2197 case PPSTATE_ESCAPED_LINE: |
|
2198 if(stringSize-curPos>1) |
|
2199 { |
|
2200 if( |
|
2201 (aText[curPos]=='\n'&&aText[curPos+1]=='\r') |
|
2202 || |
|
2203 (aText[curPos]=='\r'&&aText[curPos+1]=='\n') |
|
2204 ) |
|
2205 { |
|
2206 curPos+=2; |
|
2207 firstPos=curPos; |
|
2208 curState=PPSTATE_NORMAL; |
|
2209 } |
|
2210 else if(IsNewLine(aText[curPos])) |
|
2211 { |
|
2212 curPos+=1; |
|
2213 firstPos=curPos; |
|
2214 curState=PPSTATE_NORMAL; |
|
2215 } |
|
2216 } |
|
2217 else |
|
2218 { |
|
2219 //EOF |
|
2220 return newText; |
|
2221 } |
|
2222 |
|
2223 } |
|
2224 } |
|
2225 newText.append(aText.substr(firstPos,curPos-firstPos)); |
|
2226 return newText; |
|
2227 } |
|
2228 |
|
2229 /** |
|
2230 * C Preprocess |
|
2231 * a.remove single line comment |
|
2232 * b.remove mul-lines comment |
|
2233 * c.remove #command |
|
2234 * d.struct,NONSHARABLE_CLASS,NONSHARABLE_STRUCT --> class |
|
2235 * e.string literal -> blank string |
|
2236 */ |
|
2237 string TLeaveScanModel::PreProcess(const string& aText) |
|
2238 { |
|
2239 string afterCombine = CombineLine(aText); |
|
2240 //cout<<"before:"<<endl<<afterCombine<<endl; |
|
2241 if(afterCombine.size()<0) return string(""); |
|
2242 |
|
2243 int curPos = 0; |
|
2244 int curState = PPSTATE_NORMAL; |
|
2245 int firstPos = 0; |
|
2246 int stringSize = aText.size(); |
|
2247 int newlineCount=0; |
|
2248 int blankCount=2; |
|
2249 string newText(""); |
|
2250 while(curPos< stringSize) |
|
2251 { |
|
2252 switch(curState) |
|
2253 { |
|
2254 case PPSTATE_NORMAL: |
|
2255 { |
|
2256 char curChar = afterCombine[curPos]; |
|
2257 if(curChar=='/') |
|
2258 { |
|
2259 if(HasEnoughChar(curPos,stringSize,1)) |
|
2260 { |
|
2261 if('/'==afterCombine[curPos+1]) |
|
2262 { |
|
2263 curState=PPSTATE_SINGLE_COMMENT; |
|
2264 newText.append(afterCombine.substr(firstPos,curPos-firstPos)); |
|
2265 curPos+=2; |
|
2266 } |
|
2267 else if('*'==afterCombine[curPos+1]) |
|
2268 { |
|
2269 curState=PPSTATE_MUL_COMMENT; |
|
2270 newText.append(afterCombine.substr(firstPos,curPos-firstPos)); |
|
2271 curPos+=2; |
|
2272 } |
|
2273 else |
|
2274 { |
|
2275 curPos++; |
|
2276 } |
|
2277 } |
|
2278 else |
|
2279 { |
|
2280 curPos++; |
|
2281 } |
|
2282 } |
|
2283 else if(curChar=='"') |
|
2284 { |
|
2285 if(curPos>0&&(afterCombine[curPos-1]!='\\'&&afterCombine[curPos-1]!='\'')) |
|
2286 { |
|
2287 curState=PPSTATE_STRING_LITERAL; |
|
2288 newText.append(afterCombine.substr(firstPos,curPos-firstPos+1)); |
|
2289 |
|
2290 } |
|
2291 curPos+=1; |
|
2292 } |
|
2293 else if(curChar=='#') |
|
2294 { |
|
2295 //if # is the first non-blank char of line, comment this line |
|
2296 bool checkSharp=true; |
|
2297 for(int i=curPos-1;i>=0;i--) |
|
2298 { |
|
2299 char tmpChar = afterCombine[i]; |
|
2300 if(tmpChar==' '||tmpChar=='\t'||tmpChar=='\f') |
|
2301 { |
|
2302 continue; |
|
2303 } |
|
2304 else if(tmpChar=='\n' || tmpChar=='\t') |
|
2305 { |
|
2306 break; |
|
2307 |
|
2308 } |
|
2309 else |
|
2310 { |
|
2311 checkSharp=false; |
|
2312 break; |
|
2313 } |
|
2314 } |
|
2315 if(checkSharp) |
|
2316 { |
|
2317 curState=PPSTATE_SHARP_COMMENT; |
|
2318 newText.append(afterCombine.substr(firstPos,curPos-firstPos)); |
|
2319 } |
|
2320 curPos+=1; |
|
2321 } |
|
2322 //struct,NONSHARABLE_CLASS,NONSHARABLE_STRUCT --> class |
|
2323 else if(HasEnoughChar(curPos,stringSize,5)) |
|
2324 { |
|
2325 |
|
2326 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)) |
|
2327 { |
|
2328 newText.append(afterCombine.substr(firstPos,curPos-firstPos)); |
|
2329 newText.append("class "); |
|
2330 curPos+=6; |
|
2331 firstPos=curPos; |
|
2332 } |
|
2333 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]=='_') |
|
2334 { |
|
2335 if(HasEnoughChar(curPos,stringSize,5)) |
|
2336 { |
|
2337 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)) |
|
2338 { |
|
2339 newText.append(afterCombine.substr(firstPos,curPos-firstPos)); |
|
2340 newText.append("class"); |
|
2341 for(int i=0;i<12;i++) |
|
2342 { |
|
2343 newText.append(" "); |
|
2344 } |
|
2345 curPos+=17; |
|
2346 firstPos=curPos; |
|
2347 break; |
|
2348 } |
|
2349 } |
|
2350 if(HasEnoughChar(curPos,stringSize,6)) |
|
2351 { |
|
2352 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)) |
|
2353 { |
|
2354 newText.append(afterCombine.substr(firstPos,curPos-firstPos)); |
|
2355 newText.append("class"); |
|
2356 for(int i=0;i<13;i++) |
|
2357 { |
|
2358 newText.append(" "); |
|
2359 } |
|
2360 curPos+=18; |
|
2361 firstPos=curPos; |
|
2362 break; |
|
2363 } |
|
2364 } |
|
2365 curPos++; |
|
2366 |
|
2367 }//end of nonsharable |
|
2368 else |
|
2369 { |
|
2370 curPos++; |
|
2371 } |
|
2372 } |
|
2373 |
|
2374 else |
|
2375 { |
|
2376 curPos++; |
|
2377 } |
|
2378 break; |
|
2379 } |
|
2380 case PPSTATE_SHARP_COMMENT: |
|
2381 case PPSTATE_SINGLE_COMMENT: |
|
2382 { |
|
2383 while(curPos< stringSize) |
|
2384 { |
|
2385 if(IsNewLine(afterCombine[curPos])) |
|
2386 { |
|
2387 if(stringSize-curPos>1) |
|
2388 { |
|
2389 if( |
|
2390 (afterCombine[curPos]=='\n'&&afterCombine[curPos+1]=='\r') |
|
2391 || |
|
2392 (afterCombine[curPos]=='\r'&&afterCombine[curPos+1]=='\n') |
|
2393 ) |
|
2394 { |
|
2395 curPos+=2; |
|
2396 } |
|
2397 else |
|
2398 { |
|
2399 curPos+=1; |
|
2400 } |
|
2401 firstPos=curPos; |
|
2402 curState=PPSTATE_NORMAL; |
|
2403 newText.append("\n"); |
|
2404 break; |
|
2405 } |
|
2406 else |
|
2407 { |
|
2408 newText.append("\n"); |
|
2409 return newText; |
|
2410 } |
|
2411 } |
|
2412 else |
|
2413 { |
|
2414 curPos++; |
|
2415 } |
|
2416 } |
|
2417 firstPos=curPos; |
|
2418 |
|
2419 break; |
|
2420 } |
|
2421 case PPSTATE_MUL_COMMENT: |
|
2422 { |
|
2423 blankCount=2; |
|
2424 while(curPos< stringSize) |
|
2425 { |
|
2426 if(!HasEnoughChar(curPos,stringSize,1)) |
|
2427 { |
|
2428 return newText; |
|
2429 } |
|
2430 if(afterCombine[curPos]=='*' && afterCombine[curPos+1]=='/') |
|
2431 { |
|
2432 curPos+=2; |
|
2433 firstPos=curPos; |
|
2434 curState=PPSTATE_NORMAL; |
|
2435 blankCount+=2; |
|
2436 break; |
|
2437 } |
|
2438 else if(IsNewLine(afterCombine[curPos])) |
|
2439 { |
|
2440 if(HasEnoughChar(curPos,stringSize,1)) |
|
2441 { |
|
2442 if( |
|
2443 (afterCombine[curPos]=='\n'&&afterCombine[curPos+1]=='\r') |
|
2444 || |
|
2445 (afterCombine[curPos]=='\r'&&afterCombine[curPos+1]=='\n') |
|
2446 ) |
|
2447 { |
|
2448 curPos+=2; |
|
2449 } |
|
2450 else |
|
2451 { |
|
2452 curPos+=1; |
|
2453 } |
|
2454 } |
|
2455 else |
|
2456 { |
|
2457 curPos+=1; |
|
2458 } |
|
2459 while (blankCount-->0) |
|
2460 { |
|
2461 newText.append(" "); |
|
2462 } |
|
2463 newText.append("\n"); |
|
2464 blankCount=0; |
|
2465 } |
|
2466 else |
|
2467 { |
|
2468 curPos++; |
|
2469 blankCount++; |
|
2470 } |
|
2471 } |
|
2472 firstPos=curPos; |
|
2473 while (blankCount-->0) |
|
2474 { |
|
2475 newText.append(" "); |
|
2476 } |
|
2477 blankCount=0; |
|
2478 |
|
2479 break; |
|
2480 } |
|
2481 case PPSTATE_STRING_LITERAL: |
|
2482 blankCount=0; |
|
2483 while(curPos< stringSize) |
|
2484 { |
|
2485 |
|
2486 if((afterCombine[curPos]=='"' )&& (afterCombine[curPos-1]!='\\')) |
|
2487 { |
|
2488 curPos+=1; |
|
2489 firstPos=curPos; |
|
2490 while (blankCount-->0) |
|
2491 { |
|
2492 newText.append(" "); |
|
2493 } |
|
2494 newText.append("\""); |
|
2495 curState=PPSTATE_NORMAL; |
|
2496 break; |
|
2497 } |
|
2498 else |
|
2499 { |
|
2500 if(curPos>1 && (afterCombine[curPos]=='"' )&& (afterCombine[curPos-1]=='\\')&&(afterCombine[curPos-2]=='\\')) |
|
2501 { |
|
2502 curPos+=1; |
|
2503 firstPos=curPos; |
|
2504 while (blankCount-->0) |
|
2505 { |
|
2506 newText.append(" "); |
|
2507 } |
|
2508 newText.append("\""); |
|
2509 curState=PPSTATE_NORMAL; |
|
2510 break; |
|
2511 } |
|
2512 else |
|
2513 { |
|
2514 curPos++; |
|
2515 blankCount++; |
|
2516 } |
|
2517 } |
|
2518 } |
|
2519 break; |
|
2520 } |
|
2521 } |
|
2522 newText.append(afterCombine.substr(firstPos,curPos-firstPos)); |
|
2523 return newText; |
|
2524 } |
|
2525 /* |
|
2526 * Get next matched '{' |
|
2527 */ |
|
2528 int TLeaveScanModel::GetLeftBracket(const string& aText,uint pos) |
|
2529 { |
|
2530 int len =aText.size(); |
|
2531 if(pos>=len) |
|
2532 { |
|
2533 return string::npos; |
|
2534 } |
|
2535 while(pos<len) |
|
2536 { |
|
2537 if(aText[pos]=='{') |
|
2538 { |
|
2539 return pos; |
|
2540 } |
|
2541 pos++; |
|
2542 } |
|
2543 return string::npos; |
|
2544 } |
|
2545 /* |
|
2546 * Get next matched '}' |
|
2547 */ |
|
2548 int TLeaveScanModel::GetRightBracket(const string& aText,uint pos) |
|
2549 { |
|
2550 int len = aText.size(); |
|
2551 if(pos>=len) |
|
2552 { |
|
2553 return string::npos; |
|
2554 } |
|
2555 int parentCount = 1; |
|
2556 while(pos<len) |
|
2557 { |
|
2558 if(aText[pos]=='{') |
|
2559 { |
|
2560 parentCount++; |
|
2561 } |
|
2562 else if (aText[pos]=='}' ) |
|
2563 { |
|
2564 parentCount--; |
|
2565 if(parentCount==0) |
|
2566 { |
|
2567 return pos; |
|
2568 } |
|
2569 } |
|
2570 pos++; |
|
2571 } |
|
2572 return string::npos; |
|
2573 |
|
2574 } |
|
2575 /* |
|
2576 Get next '(' |
|
2577 */ |
|
2578 int TLeaveScanModel::GetLeftParenthesis(const string& aText,uint pos) |
|
2579 { |
|
2580 int len =aText.size(); |
|
2581 if(pos>=len) |
|
2582 { |
|
2583 return string::npos; |
|
2584 } |
|
2585 while(pos<len) |
|
2586 { |
|
2587 char curChar = aText[pos]; |
|
2588 if(curChar=='(') |
|
2589 { |
|
2590 return pos; |
|
2591 } |
|
2592 pos++; |
|
2593 } |
|
2594 return string::npos; |
|
2595 } |
|
2596 |
|
2597 /* |
|
2598 * Get next matched ')' |
|
2599 */ |
|
2600 int TLeaveScanModel::GetRightParenthesis(const string& aText,uint pos) |
|
2601 { |
|
2602 int len = aText.size(); |
|
2603 if(pos>=len) |
|
2604 { |
|
2605 return string::npos; |
|
2606 } |
|
2607 int parentCount = 1; |
|
2608 while(pos<len) |
|
2609 { |
|
2610 char curChar = aText[pos]; |
|
2611 if(curChar=='(') |
|
2612 { |
|
2613 parentCount++; |
|
2614 } |
|
2615 else if (curChar==')' ) |
|
2616 { |
|
2617 parentCount--; |
|
2618 if(parentCount==0) |
|
2619 { |
|
2620 return pos; |
|
2621 } |
|
2622 } |
|
2623 pos++; |
|
2624 } |
|
2625 return string::npos; |
|
2626 } |
|
2627 |
|
2628 /* |
|
2629 Get next '<' by pair |
|
2630 */ |
|
2631 int TLeaveScanModel::GetLeftTmpltParentBack(const string& aText,uint pos) |
|
2632 { |
|
2633 int count=1; |
|
2634 if (pos<=0) |
|
2635 { |
|
2636 return string::npos; |
|
2637 } |
|
2638 while(pos>0) |
|
2639 { |
|
2640 char curChar = aText[pos]; |
|
2641 if(curChar=='<') |
|
2642 { |
|
2643 count--; |
|
2644 if (count <= 0) |
|
2645 return pos; |
|
2646 } |
|
2647 else if(curChar=='>') |
|
2648 { |
|
2649 count++; |
|
2650 } |
|
2651 pos--; |
|
2652 } |
|
2653 return string::npos; |
|
2654 } |
|
2655 |
|
2656 /* |
|
2657 * Get next matched '>' |
|
2658 */ |
|
2659 int TLeaveScanModel::GetRightTmpltParent(const string& aText,uint pos) |
|
2660 { |
|
2661 int len = aText.size(); |
|
2662 if(pos>=len) |
|
2663 { |
|
2664 return string::npos; |
|
2665 } |
|
2666 int parentCount = 1; |
|
2667 while(pos<len) |
|
2668 { |
|
2669 char curChar = aText[pos]; |
|
2670 if(curChar=='<') |
|
2671 { |
|
2672 parentCount++; |
|
2673 } |
|
2674 else if (curChar=='>' ) |
|
2675 { |
|
2676 parentCount--; |
|
2677 if(parentCount==0) |
|
2678 { |
|
2679 return pos; |
|
2680 } |
|
2681 } |
|
2682 pos++; |
|
2683 } |
|
2684 return string::npos; |
|
2685 } |
|
2686 |
|
2687 /* |
|
2688 *Get the start and end position of a class |
|
2689 */ |
|
2690 list<ClassMeta> TLeaveScanModel::GetClass(const string& aFile) |
|
2691 { |
|
2692 int len= aFile.size(); |
|
2693 int startPos=0; |
|
2694 int nextClassPos=-1; |
|
2695 list<ClassMeta> classList; |
|
2696 //struct ,NONSHARABLE_CLASS,NONSHARABLE_STRUCT should be parsed to 'class' in pp stage |
|
2697 while((nextClassPos = aFile.find("class",startPos))!=string::npos) |
|
2698 { |
|
2699 |
|
2700 |
|
2701 char classSuffix = aFile[nextClassPos+5]; //the char after class |
|
2702 if(classSuffix!=' '&& classSuffix!='\n' && classSuffix!='\r' && classSuffix!='\t'&& classSuffix!=':'&&classSuffix!='{') |
|
2703 { |
|
2704 nextClassPos++; |
|
2705 startPos=nextClassPos; |
|
2706 continue; |
|
2707 } |
|
2708 /*no use*/ |
|
2709 /* |
|
2710 if(nextClassPos>0) |
|
2711 { |
|
2712 char classPrfix = aFile[nextClassPos-1]; |
|
2713 if (classPrfix =='_' || (classPrfix>='a' && classPrfix<='z') || (classPrfix>='A' && classPrfix<='Z') || (classPrfix>='0' && classPrfix<='9')) |
|
2714 { |
|
2715 nextClassPos++; |
|
2716 startPos=nextClassPos; |
|
2717 continue; |
|
2718 } |
|
2719 } |
|
2720 */ |
|
2721 if(nextClassPos >0 ) |
|
2722 { |
|
2723 char classPrefix = aFile[nextClassPos-1]; |
|
2724 if(classPrefix!=' '&& classPrefix!='\n' && classPrefix!='\r' && classPrefix!='\t'&& classPrefix!='{'&& classPrefix!='>'&& classPrefix!='}') |
|
2725 { |
|
2726 nextClassPos++; |
|
2727 startPos=nextClassPos; |
|
2728 continue; |
|
2729 } |
|
2730 } |
|
2731 |
|
2732 //pattern: template< ...class...> |
|
2733 int checkTemplate = nextClassPos-1; |
|
2734 bool isTemplateClass = false; |
|
2735 while(checkTemplate >= 0) |
|
2736 { |
|
2737 char checkTempChar = aFile[checkTemplate]; |
|
2738 if(checkTempChar==' '|| checkTempChar=='\n' || checkTempChar=='\r' ||checkTempChar=='\t') |
|
2739 { |
|
2740 checkTemplate --; |
|
2741 } |
|
2742 else if(checkTempChar=='>') //template<> class |
|
2743 { |
|
2744 break; |
|
2745 } |
|
2746 else if(checkTempChar=='<') |
|
2747 { |
|
2748 isTemplateClass =true; |
|
2749 break; |
|
2750 } |
|
2751 else if(checkTempChar==',') //template<typename a, class T> |
|
2752 { |
|
2753 isTemplateClass =true; |
|
2754 break; |
|
2755 } |
|
2756 else |
|
2757 { |
|
2758 break; |
|
2759 } |
|
2760 } |
|
2761 if(isTemplateClass) |
|
2762 { |
|
2763 startPos = nextClassPos+1; |
|
2764 continue; |
|
2765 } |
|
2766 |
|
2767 int classStart = GetLeftBracket(aFile,nextClassPos); |
|
2768 if(classStart==-1) |
|
2769 { |
|
2770 break; //there is no more class-body, so we can break dircetly |
|
2771 } |
|
2772 //skip this pattern |
|
2773 //class a; |
|
2774 uint semiPos = aFile.find(";",nextClassPos); |
|
2775 //such as this pattern: |
|
2776 //class a; |
|
2777 //class b{}; |
|
2778 if(semiPos!=string::npos&&semiPos<classStart) |
|
2779 { |
|
2780 startPos = semiPos; |
|
2781 continue; |
|
2782 } |
|
2783 |
|
2784 uint classEnd = GetRightBracket(aFile,classStart+1); |
|
2785 if(classEnd == -1) |
|
2786 { |
|
2787 classEnd = len-1; |
|
2788 } |
|
2789 |
|
2790 //get class name |
|
2791 int curClassNamePos = classStart-1; |
|
2792 char curClassChar = 0; |
|
2793 //find pattern: |
|
2794 //class a:publlc b{... |
|
2795 uint colonPos = aFile.find(":",nextClassPos); |
|
2796 while(colonPos!=string::npos && colonPos<curClassNamePos) |
|
2797 { |
|
2798 if(colonPos != string::npos && colonPos < classStart) |
|
2799 { |
|
2800 uint secondColonPos = aFile.find(":",colonPos+1); |
|
2801 if(secondColonPos != string::npos && secondColonPos!=(colonPos+1)) |
|
2802 { |
|
2803 curClassNamePos = colonPos-1; |
|
2804 break; |
|
2805 } |
|
2806 else if(secondColonPos == string::npos) |
|
2807 { |
|
2808 curClassNamePos = colonPos-1; |
|
2809 break; |
|
2810 } |
|
2811 //find :: |
|
2812 else |
|
2813 { |
|
2814 colonPos = aFile.find(":",colonPos+2); |
|
2815 } |
|
2816 } |
|
2817 } |
|
2818 //skip white spaces |
|
2819 while(curClassNamePos >= nextClassPos) |
|
2820 { |
|
2821 curClassChar = aFile[curClassNamePos]; |
|
2822 if(curClassChar ==' ' || curClassChar =='\t' || curClassChar =='\n' ||curClassChar=='\r' ||curClassChar==')') |
|
2823 { |
|
2824 curClassNamePos--; |
|
2825 } |
|
2826 else |
|
2827 { |
|
2828 break; |
|
2829 } |
|
2830 } |
|
2831 int classNameEnd = curClassNamePos; |
|
2832 while(curClassNamePos>=nextClassPos) |
|
2833 { |
|
2834 curClassChar = aFile[curClassNamePos]; |
|
2835 if(curClassChar ==' ' || curClassChar =='\t' || curClassChar =='\n' ||curClassChar=='\r'||curClassChar==':'||curClassChar=='(') |
|
2836 { |
|
2837 break; |
|
2838 } |
|
2839 else |
|
2840 { |
|
2841 curClassNamePos--; |
|
2842 } |
|
2843 } |
|
2844 int classNameStart = curClassNamePos+1; //cur is a blank |
|
2845 string curClassName = TrimString(aFile.substr(classNameStart,classNameEnd-classNameStart+1)); |
|
2846 if (curClassName == "class") |
|
2847 { |
|
2848 curClassName = "anonymous-class"; |
|
2849 } |
|
2850 ClassMeta curClass; |
|
2851 curClass.startPos=classStart; |
|
2852 curClass.endPos=classEnd; |
|
2853 curClass.className = curClassName; |
|
2854 classList.push_back(curClass); |
|
2855 startPos=nextClassPos+1; |
|
2856 } |
|
2857 return classList; |
|
2858 } |
|
2859 |
|
2860 /* |
|
2861 * parse the class and check it |
|
2862 * */ |
|
2863 void TLeaveScanModel::CheckClass(const string& aText ,const string& aClassName , uint start,uint end) |
|
2864 { |
|
2865 start=start+1; |
|
2866 int curPos = start; |
|
2867 end=end-1; |
|
2868 if(end<=start) return; |
|
2869 //int colonCount=0; |
|
2870 int curStart= curPos; |
|
2871 int curEnd = curStart; |
|
2872 int curType = E_NA; |
|
2873 int curLine = 0; // wrong!!! |
|
2874 int len = aText.size(); |
|
2875 string functionHead=""; |
|
2876 string functionArgu=""; |
|
2877 string functionBody=""; |
|
2878 string memberDef=""; |
|
2879 |
|
2880 for(curPos = start;curPos<=end;curPos++) |
|
2881 { |
|
2882 char curChar = aText[curPos]; |
|
2883 switch(curChar) |
|
2884 { |
|
2885 case ':': |
|
2886 if (aText[curPos+1]==':')// a '::' |
|
2887 { |
|
2888 //skip second : |
|
2889 curPos+=1; |
|
2890 } |
|
2891 //such as ctor_init_list |
|
2892 else if(curType == E_MemberFunctionDecl || curType==E_MemberFunctionDef) |
|
2893 { |
|
2894 //nothing |
|
2895 } |
|
2896 else //such as "public:" ->ignore |
|
2897 { |
|
2898 curStart = curPos+1; |
|
2899 } |
|
2900 break; |
|
2901 case '{': |
|
2902 if(curType ==E_MemberFunctionDecl ) |
|
2903 { |
|
2904 curType = E_MemberFunctionDef; |
|
2905 } |
|
2906 else |
|
2907 { |
|
2908 curType = E_Enum; |
|
2909 } |
|
2910 curEnd = GetRightBracket(aText,curPos+1); |
|
2911 functionBody = aText.substr(curPos,curEnd-curPos+1); |
|
2912 //check in class function |
|
2913 if(E_MemberFunctionDef==curType) |
|
2914 { |
|
2915 CheckInClassFunc(aText,aClassName,functionHead,curPos,curEnd); |
|
2916 } |
|
2917 curPos = curEnd; |
|
2918 curStart =curPos; |
|
2919 curType = E_NA; |
|
2920 break; |
|
2921 case '(': |
|
2922 curType = E_MemberFunctionDecl; |
|
2923 curEnd = GetRightParenthesis(aText,curPos+1); |
|
2924 functionHead = aText.substr(curStart,curPos-curStart); |
|
2925 functionArgu = aText.substr(curPos,curEnd-curPos+1); |
|
2926 curPos = curEnd; |
|
2927 curStart =curPos; |
|
2928 |
|
2929 break; |
|
2930 case ';': |
|
2931 if(curType == E_NA) |
|
2932 { |
|
2933 curType = E_MemberData; |
|
2934 } |
|
2935 //check point |
|
2936 if (curType == E_MemberData) |
|
2937 { |
|
2938 memberDef = aText.substr(curStart,curPos-curStart); |
|
2939 if(memberDef.find("LCleanedup")!=string::npos) |
|
2940 { |
|
2941 iErrorString = "class "+aClassName+" defines a data member with LCleanedup* type.\n"; |
|
2942 cout<<GetErrorLineHead(aText, curPos)<<iErrorString; |
|
2943 } |
|
2944 } |
|
2945 else if(curType == E_MemberFunctionDecl) |
|
2946 { |
|
2947 string funcName = GetFunctNameFromFuncHead(functionHead); |
|
2948 string extraTypes="CDX"; |
|
2949 bool isLeaver = false; |
|
2950 if (funcName[funcName.length()-1] == 'L' || |
|
2951 (funcName[funcName.length()-2] == 'L' && string::npos != extraTypes.find(funcName[funcName.length()-1]) ) ) |
|
2952 { |
|
2953 isLeaver = true; // container is marked Leaver - used to return here |
|
2954 } |
|
2955 else if(IsLClassCtor(aClassName+"::"+funcName)) |
|
2956 { |
|
2957 isLeaver = true; |
|
2958 } |
|
2959 else |
|
2960 isLeaver = false; // container not marked Leaver |
|
2961 |
|
2962 |
|
2963 if(functionHead.find("LString")!=string::npos ||functionHead.find("LData")!=string::npos) |
|
2964 { |
|
2965 iErrorString = aClassName+"::"+funcName+" returns LString/LData class.\n"; |
|
2966 if(!isLeaver) cout<<GetErrorLineHead(aText, curPos)<<iErrorString; |
|
2967 } |
|
2968 if(functionArgu.find("LString")!=string::npos ||functionArgu.find("LData")!=string::npos) |
|
2969 { |
|
2970 iErrorString = aClassName+"::"+funcName+" uses LString/LData class as parameter.\n"; |
|
2971 if(!isLeaver) cout<<GetErrorLineHead(aText, curPos)<<iErrorString; |
|
2972 } |
|
2973 } |
|
2974 //set up next check |
|
2975 curStart = curPos; |
|
2976 curType =E_NA; |
|
2977 break; |
|
2978 case 'c': |
|
2979 //check if 'class' and skip the inner class |
|
2980 if (HasEnoughChar(curPos,len,5)) |
|
2981 { |
|
2982 if ( aText[curPos+1]=='l' && aText[curPos+2]=='a' && aText[curPos+3]=='s' && aText[curPos+4]=='s' ) |
|
2983 { |
|
2984 char delimiter = aText[curPos+5]; |
|
2985 //exclude pattern: void classa () |
|
2986 if (!((delimiter >='0' && delimiter <='9') || (delimiter>='a' && delimiter<='z') || (delimiter>='A' && delimiter<='Z') ||(delimiter=='_'))) |
|
2987 { |
|
2988 delimiter = aText[curPos-1]; |
|
2989 //exclude pattern: void aclass() |
|
2990 if(curPos>0 && !((delimiter >='0' && delimiter <='9') || (delimiter>='a' && delimiter<='z') || (delimiter>='A' && delimiter<='Z') ||(delimiter=='_'))) |
|
2991 { |
|
2992 //pattern: template<class T> Ltemp(T x){} |
|
2993 uint templatePos = aText.find("template",curStart); |
|
2994 if(templatePos != string::npos && templatePos < curPos) |
|
2995 { |
|
2996 continue; |
|
2997 } |
|
2998 else |
|
2999 { |
|
3000 int tmpLeft = GetLeftBracket(aText,curPos+4); |
|
3001 int tempRight = GetRightBracket(aText,tmpLeft+1); |
|
3002 curPos = tempRight; |
|
3003 curStart = curPos; |
|
3004 curType = E_NA; |
|
3005 } |
|
3006 } |
|
3007 } |
|
3008 |
|
3009 } |
|
3010 } |
|
3011 //ignore |
|
3012 break; |
|
3013 default: |
|
3014 //curPos++; |
|
3015 break; |
|
3016 } |
|
3017 //curPos++; |
|
3018 } |
|
3019 } |
|
3020 /* |
|
3021 * Is a ctor of L class |
|
3022 * */ |
|
3023 bool TLeaveScanModel::IsLClassCtor(const string& aName) |
|
3024 { |
|
3025 |
|
3026 //if(aName[0]=='L'&&aName.find("::")!=string::npos)% |
|
3027 //{ |
|
3028 // return true; |
|
3029 //} |
|
3030 uint colonPos = aName.find("::"); |
|
3031 if(colonPos == string::npos) |
|
3032 { |
|
3033 return false; |
|
3034 } |
|
3035 string s1 = aName.substr(0,colonPos); |
|
3036 string s2 = aName.substr(colonPos+2); |
|
3037 s1.erase(s1.find_last_not_of(" \t\n\r")+1); |
|
3038 s1.erase(0,s1.find_first_not_of(" \t\n\r")); |
|
3039 |
|
3040 s2.erase(s2.find_last_not_of(" \t\n\r")+1); |
|
3041 s2.erase(0,s2.find_first_not_of(" \t\n\r")); |
|
3042 |
|
3043 |
|
3044 uint tmpltPos = s1.find('<'); |
|
3045 if(tmpltPos!=string::npos) |
|
3046 { |
|
3047 s1 = s1.substr(0,tmpltPos); |
|
3048 } |
|
3049 if(s1[0]!='L') |
|
3050 { |
|
3051 return false; |
|
3052 } |
|
3053 if(s1.find(s2)!=string::npos) |
|
3054 { |
|
3055 uint s1Len = s1.length(); |
|
3056 uint s2Len = s2.length(); |
|
3057 //s1=LAL |
|
3058 //s2=LA |
|
3059 if(s2Len>0 && s1Len > s2Len) |
|
3060 { |
|
3061 char diffChar = s1[s2Len]; |
|
3062 if( (diffChar>='a' && diffChar<='z') || (diffChar>='A' && diffChar<='Z') |
|
3063 ||(diffChar>='0' && diffChar<='9') || (diffChar=='_')) |
|
3064 { |
|
3065 return false; |
|
3066 } |
|
3067 } |
|
3068 return true; |
|
3069 } |
|
3070 if(s2.find("operator")==0) |
|
3071 { |
|
3072 return true; |
|
3073 } |
|
3074 if(s2.find("new")==0) |
|
3075 { |
|
3076 return true; |
|
3077 } |
|
3078 |
|
3079 return false; |
|
3080 } |
|
3081 /* |
|
3082 * Is sometiing defined in class scope? |
|
3083 */ |
|
3084 bool TLeaveScanModel::IsInClassScope(uint pos) |
|
3085 { |
|
3086 if (pos == string::npos) |
|
3087 { |
|
3088 return false; |
|
3089 } |
|
3090 list<ClassMeta>::iterator iter; |
|
3091 for(iter=iClassList.begin();iter!=iClassList.end();iter++) |
|
3092 { |
|
3093 if(iter->startPos<=pos && iter->endPos >= pos) |
|
3094 { |
|
3095 return true; |
|
3096 } |
|
3097 } |
|
3098 return false; |
|
3099 |
|
3100 } |
|
3101 /* |
|
3102 * Try to get the function name from a function head |
|
3103 * */ |
|
3104 string TLeaveScanModel::GetFunctNameFromFuncHead(const string& aFuncHead) |
|
3105 { |
|
3106 string funcName; |
|
3107 int len = aFuncHead.length(); |
|
3108 int curPos=len-1; |
|
3109 char curChar; |
|
3110 int nameStart = -1; |
|
3111 int nameEnd; |
|
3112 //skip white spaces |
|
3113 while(curPos>=0) |
|
3114 { |
|
3115 curChar = aFuncHead[curPos]; |
|
3116 if(curChar==' ' || curChar=='\t' ||curChar=='\n'||curChar=='\r') |
|
3117 { |
|
3118 curPos--; |
|
3119 } |
|
3120 else |
|
3121 { |
|
3122 break; |
|
3123 } |
|
3124 } |
|
3125 if(curChar == '>') |
|
3126 { |
|
3127 int templateBalance = 1; |
|
3128 curPos--; |
|
3129 while(curPos>=0) |
|
3130 { |
|
3131 curChar = aFuncHead[curPos]; |
|
3132 |
|
3133 if(curChar=='>') |
|
3134 { |
|
3135 templateBalance++; |
|
3136 } |
|
3137 else if(curChar =='<') |
|
3138 { |
|
3139 templateBalance--; |
|
3140 } |
|
3141 curPos--; |
|
3142 if(templateBalance==0) |
|
3143 { |
|
3144 break; |
|
3145 } |
|
3146 |
|
3147 } |
|
3148 } |
|
3149 if(curPos<=0) return ""; |
|
3150 |
|
3151 nameEnd = curPos; |
|
3152 if(aFuncHead.find("operator")!=string::npos) |
|
3153 { |
|
3154 int tmpNameStart = aFuncHead.find("operator"); |
|
3155 char delimiter = aFuncHead[tmpNameStart+8]; |
|
3156 if (!((delimiter >='0' && delimiter <='9') || (delimiter>='a' && delimiter<='z') || (delimiter>='A' && delimiter<='Z') ||(delimiter=='_'))) |
|
3157 { |
|
3158 if(tmpNameStart>0) |
|
3159 { |
|
3160 delimiter = aFuncHead[tmpNameStart-1]; |
|
3161 if (!((delimiter >='0' && delimiter <='9') || (delimiter>='a' && delimiter<='z') || (delimiter>='A' && delimiter<='Z') ||(delimiter=='_'))) |
|
3162 { |
|
3163 nameStart = tmpNameStart; |
|
3164 } |
|
3165 } |
|
3166 if(tmpNameStart==0) |
|
3167 { |
|
3168 nameStart = tmpNameStart; |
|
3169 } |
|
3170 } |
|
3171 } |
|
3172 if(nameStart == -1) |
|
3173 { |
|
3174 while(curPos>=0) |
|
3175 { |
|
3176 curChar = aFuncHead[curPos]; |
|
3177 if(curChar==' ' || curChar=='\t' ||curChar=='\n'||curChar=='\r'||curChar=='>') |
|
3178 { |
|
3179 nameStart = curPos+1; |
|
3180 if(nameStart<0) |
|
3181 { |
|
3182 nameStart = 0; |
|
3183 } |
|
3184 break; |
|
3185 |
|
3186 } |
|
3187 else |
|
3188 { |
|
3189 curPos--; |
|
3190 } |
|
3191 |
|
3192 } |
|
3193 if(curPos<0) |
|
3194 { |
|
3195 nameStart = 0; |
|
3196 } |
|
3197 } |
|
3198 funcName = aFuncHead.substr(nameStart,nameEnd-nameStart+1); |
|
3199 return funcName; |
|
3200 |
|
3201 |
|
3202 } |
|
3203 /* |
|
3204 * Get the Param string of a function decl |
|
3205 * aStart usually is the position of '{' |
|
3206 * */ |
|
3207 string TLeaveScanModel::GetFunctionParam(const string& aText, uint aStart) |
|
3208 { |
|
3209 int curPos = aStart; |
|
3210 if(curPos == string::npos) |
|
3211 { |
|
3212 return ""; |
|
3213 } |
|
3214 int leftParenthesis = GetLeftParenthesis(aText, curPos); |
|
3215 int rightParenthesis = GetRightParenthesis(aText, leftParenthesis+1); |
|
3216 |
|
3217 if(leftParenthesis==string::npos || rightParenthesis==string::npos) |
|
3218 { |
|
3219 return ""; |
|
3220 } |
|
3221 else if(rightParenthesis>leftParenthesis) |
|
3222 { |
|
3223 return aText.substr(leftParenthesis+1, rightParenthesis-leftParenthesis-1); |
|
3224 } |
|
3225 return ""; |
|
3226 |
|
3227 |
|
3228 } |
|
3229 |
|
3230 /*Get the string from last member decl to aStart*/ |
|
3231 string TLeaveScanModel::GetFunctionHead(const string& aText, uint aStart) |
|
3232 { |
|
3233 int curPos = aStart; |
|
3234 char curChar; |
|
3235 if(curPos==string::npos || curPos<=0) |
|
3236 { |
|
3237 return ""; |
|
3238 } |
|
3239 while(curPos >= 0) |
|
3240 { |
|
3241 curChar = aText[curPos]; |
|
3242 if(curChar == '{' || curChar == '}' || curChar == ';') |
|
3243 { |
|
3244 break; |
|
3245 } |
|
3246 curPos--; |
|
3247 } |
|
3248 if(curPos<0) |
|
3249 { |
|
3250 curPos = 0; |
|
3251 } |
|
3252 |
|
3253 int tempPos = string::npos; |
|
3254 if( (aText.rfind("public",aStart)!=string::npos)||(aText.rfind("protected",aStart))!=string::npos ||(aText.rfind("private",aStart))!=string::npos) |
|
3255 { |
|
3256 tempPos = aText.rfind(':',aStart); |
|
3257 |
|
3258 } |
|
3259 if(tempPos>curPos) |
|
3260 { |
|
3261 curPos = tempPos; |
|
3262 } |
|
3263 return aText.substr(curPos,aStart-curPos); |
|
3264 |
|
3265 } |
|
3266 /*Chech the function decl/define in a class*/ |
|
3267 void TLeaveScanModel::CheckInClassFunc(const string& aText , const string& aClassName, const string& aFuncName, uint start,uint end) |
|
3268 { |
|
3269 bool isLeaver; |
|
3270 bool clean; |
|
3271 string funcName = TrimString(GetFunctNameFromFuncHead(aFuncName)); |
|
3272 string qualifiedFuncName = aClassName+"::"+funcName; |
|
3273 clean = CheckFunc(aText, funcName, start, end, isLeaver); |
|
3274 bool isLCFunc =false; |
|
3275 if(funcName[funcName.length()-1] == 'C' && funcName[funcName.length()-2] == 'L') |
|
3276 { |
|
3277 isLCFunc = true; |
|
3278 } |
|
3279 if (isLeaver) // was a leaving container(safe) and no leavers found |
|
3280 { |
|
3281 |
|
3282 if (clean) |
|
3283 { |
|
3284 iPositionOfError=0; |
|
3285 iErrorString = "Warning - " + funcName + " appears to contain no leavers."; |
|
3286 ReportErrorLineAndString(start); |
|
3287 } |
|
3288 else if(isLCFunc) |
|
3289 { |
|
3290 |
|
3291 uint lcleanedupPos = iErrorString.find("LCleanedup"); |
|
3292 if(lcleanedupPos!=string::npos) |
|
3293 { |
|
3294 uint callPos = iErrorString.find(" calls "); |
|
3295 uint lcleanedupPosInFuncName = funcName.find("LCleanedup"); |
|
3296 if(callPos!=string::npos && lcleanedupPosInFuncName!=string::npos && lcleanedupPos<callPos) |
|
3297 {;} |
|
3298 else |
|
3299 { |
|
3300 iErrorString = "LCleanedup class is used in a function suffixed LC"; |
|
3301 ReportErrorLineAndString(start); |
|
3302 } |
|
3303 } |
|
3304 } |
|
3305 |
|
3306 // any leavers info can be supressed here since container was leaver |
|
3307 } |
|
3308 else // wasn't a leaving container |
|
3309 { |
|
3310 if (!clean) // was dirty, so report |
|
3311 ReportErrorLineAndString(start); |
|
3312 } |
|
3313 }; |
|
3314 |
|
3315 // |
|
3316 // Some test functions (for when leavescan parses its own source code) |
|
3317 // |
|
3318 void TLeaveScanModel::Test1() |
|
3319 { |
|
3320 Test2L(); |
|
3321 } |
|
3322 |
|
3323 void TLeaveScanModel::Test2L() |
|
3324 { |
|
3325 Test1(); |
|
3326 } |
|
3327 |
|
3328 #define TEST2L Test2L |
|
3329 void TLeaveScanModel::Test3() |
|
3330 { |
|
3331 TEST2L(); |
|
3332 } |
|
3333 |
|
3334 void TLeaveScanModel::Test4() |
|
3335 { |
|
3336 Test2L(); // qualify me |
|
3337 }; |
|
3338 |
|
3339 |
|
3340 |
|
3341 // warnings back to default levels |
|
3342 //#pragma warning (pop) |
|
3343 |