|
1 /* |
|
2 * Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include "CmdGlobals.h" |
|
20 #ifdef __WIN__ |
|
21 #pragma warning(disable:4786) |
|
22 #endif |
|
23 |
|
24 #include <iostream> |
|
25 #include <fstream> |
|
26 #include <string> |
|
27 #include <map> |
|
28 #include <list> |
|
29 #include "Utils.h" |
|
30 #include "TChange.h" |
|
31 #include "HAException.h" |
|
32 |
|
33 using namespace std; |
|
34 |
|
35 #include "MacroAnalyser.h" |
|
36 |
|
37 // ---------------------------------------------------------------------------- |
|
38 // MacroAnalyser::MacroAnalyser |
|
39 // ---------------------------------------------------------------------------- |
|
40 // |
|
41 MacroAnalyser::MacroAnalyser(string filebase, string filecurrent, vector<string> basebundle, vector<string> currentbundle) |
|
42 :iBaseFile(filebase), iCurrentFile(filecurrent), iBaseBundle(basebundle), iCurrentBundle(currentbundle) |
|
43 { |
|
44 } |
|
45 |
|
46 // ---------------------------------------------------------------------------- |
|
47 // MacroAnalyser::~MacroAnalyser |
|
48 // ---------------------------------------------------------------------------- |
|
49 // |
|
50 MacroAnalyser::~MacroAnalyser(void) |
|
51 { |
|
52 } |
|
53 |
|
54 // ---------------------------------------------------------------------------- |
|
55 // MacroAnalyser::Analyse |
|
56 // ---------------------------------------------------------------------------- |
|
57 // |
|
58 void MacroAnalyser::Analyse(list<string>& aMacroFiles) |
|
59 { |
|
60 ifstream basefile(iBaseFile.c_str(), ios::in); |
|
61 ifstream currentfile(iCurrentFile.c_str(), ios::in); |
|
62 |
|
63 map<string, list<pair<pair<string, string>,string> > > baseline; |
|
64 map<string, list<pair<pair<string, string>,string> > > current; |
|
65 |
|
66 baseline = parseMacros(basefile, iBaseBundle, &iRemoved, true); |
|
67 current = parseMacros(currentfile, iCurrentBundle); |
|
68 |
|
69 vector<string>::iterator curbegin = iCurrentBundle.begin(); |
|
70 vector<string>::iterator curend = iCurrentBundle.end(); |
|
71 vector<string>::iterator basebegin = iBaseBundle.begin(); |
|
72 vector<string>::iterator baseend = iBaseBundle.end(); |
|
73 map<string, TChange<list<pair<string,string> > > >::iterator removedbegin; |
|
74 for(;curbegin != curend; curbegin++) |
|
75 { |
|
76 string curfilename = *curbegin; |
|
77 string basefilename; |
|
78 if( basebegin != iBaseBundle.end() ) |
|
79 { |
|
80 basefilename = *basebegin; |
|
81 } |
|
82 else |
|
83 { |
|
84 continue; |
|
85 } |
|
86 removedbegin = iRemoved.find(basefilename); |
|
87 if (removedbegin != iRemoved.end()) |
|
88 { |
|
89 map<string, list<pair<pair<string, string>,string> > >::iterator cur = current.find(curfilename); |
|
90 if (cur == current.end()) // We need to check if there is a list with given filename |
|
91 // because they aren't created in situation where there isn't any macros |
|
92 { // specific to that file or the include guard for the file is duplicated. |
|
93 list<pair<pair<string, string>,string> > tempvar; |
|
94 pair<string, list<pair<pair<string, string>,string> > > tempvar2(curfilename, tempvar); |
|
95 pair<map<string, list<pair<pair<string, string>,string> > >::iterator, bool > pos = current.insert(tempvar2); |
|
96 if (pos.second == true) |
|
97 { |
|
98 cur = pos.first; |
|
99 } else |
|
100 { // this shouldn't be happening |
|
101 throw HAException("Problems ahead."); |
|
102 } |
|
103 } |
|
104 map<string, list<pair<pair<string, string>,string> > >::iterator base = baseline.find(basefilename); |
|
105 findDuplicates(basefilename,curfilename,base->second, cur->second, removedbegin->second, iBaseDuplicates, iCurrentDuplicates); |
|
106 |
|
107 //maintain a cache list of files with macros |
|
108 if(base->second.size() > 0) |
|
109 aMacroFiles.push_back(toLowerCaseWin(base->first)); |
|
110 if(cur->second.size() > 0) |
|
111 aMacroFiles.push_back(toLowerCaseWin(cur->first)); |
|
112 |
|
113 // After next loop we will have in list only those which has been either removed or changed |
|
114 list<pair<pair<string, string>,string> >::iterator begin = cur->second.begin(); |
|
115 list<pair<pair<string, string>,string> >::iterator end = cur->second.end(); |
|
116 for(;begin != end; begin++) |
|
117 { |
|
118 list<pair<string,string> >::iterator place = FindFromList(begin->first.first, removedbegin->second.GetValue()); |
|
119 if (place != removedbegin->second.GetValue().end()) |
|
120 { |
|
121 removedbegin->second.GetValue().erase(place); // we found macro with same name so we can remove it |
|
122 list<pair<pair<string, string>,string> > baselist = base->second; |
|
123 list<pair<pair<string, string>,string> >::iterator found = FindFromList(begin->first.first, baselist, ELeftValue); |
|
124 if (found != baselist.end()) |
|
125 { |
|
126 if (found->first.second != begin->first.second) |
|
127 { // Contents of macro are different so we need to add the macro to changed list |
|
128 pair<pair<string,string>,string> changes; |
|
129 changes.first.first = found->first.second; |
|
130 changes.first.second = begin->first.second; |
|
131 changes.second = begin->second; |
|
132 pair<string, pair<pair<string, string>,string> > param(begin->first.first,changes); |
|
133 map<string, TChange<map<string, pair<pair<string, string>,string> > > >::iterator file = iChanged.find(basefilename); |
|
134 if (file != iChanged.end()) |
|
135 { |
|
136 file->second.GetValue().insert(param); |
|
137 } else |
|
138 { |
|
139 map<string, pair<pair<string, string>,string> > tempvar; |
|
140 tempvar.insert(param); |
|
141 TChange<map<string, pair<pair<string, string>,string> > > tempvar2(basefilename, curfilename, tempvar); |
|
142 pair<string, TChange<map<string, pair<pair<string, string>,string> > > > tempvar3(basefilename, tempvar2); |
|
143 iChanged.insert(tempvar3); |
|
144 } |
|
145 } |
|
146 } |
|
147 } |
|
148 } |
|
149 removedbegin->second.SetCurrent(curfilename); |
|
150 } |
|
151 basebegin++; |
|
152 } |
|
153 } |
|
154 |
|
155 // ---------------------------------------------------------------------------- |
|
156 // MacroAnalyser::FindMacro |
|
157 // ---------------------------------------------------------------------------- |
|
158 // |
|
159 pair<string, string> MacroAnalyser::FindMacro(string aLine) |
|
160 { |
|
161 pair<string, string> ret; |
|
162 string::size_type pos = aLine.find_first_of(" \t"); |
|
163 while(pos != string::npos && (aLine.at(pos) == ' ' || aLine.at(pos) == '\t') ) |
|
164 pos++; |
|
165 string::size_type param_pos = pos ; |
|
166 pos = aLine.find_first_of(" \t(",param_pos); |
|
167 string value; |
|
168 if (pos != string::npos && aLine.at(pos) == '(') |
|
169 { |
|
170 pos = aLine.find(')',pos); |
|
171 if(pos !=string::npos ) |
|
172 pos++; |
|
173 } |
|
174 if (pos != string::npos && pos < aLine.size()) |
|
175 { // only if there is stuff after name of macro we put it to value |
|
176 size_t value_pos = (unsigned int)pos + 1; |
|
177 value = aLine.substr(value_pos); |
|
178 value = trimWhiteSpace(value); |
|
179 if (value.size() != 0) |
|
180 { |
|
181 value_pos = value.find_first_not_of(" \t"); |
|
182 if (value_pos != string::npos && value_pos != 0) |
|
183 { |
|
184 value = value.substr(value_pos); |
|
185 } |
|
186 } |
|
187 } else |
|
188 { // otherwise we put empty value |
|
189 value = ""; |
|
190 } |
|
191 |
|
192 string param = aLine.substr(param_pos, pos - param_pos); |
|
193 ret = pair<string,string>(param,value); |
|
194 return ret; |
|
195 } |
|
196 |
|
197 // ---------------------------------------------------------------------------- |
|
198 // MacroAnalyser::getRemoved |
|
199 // ---------------------------------------------------------------------------- |
|
200 // |
|
201 map<string, TChange<list<pair<string,string> > > >& MacroAnalyser::getRemoved() |
|
202 { |
|
203 return iRemoved; |
|
204 } |
|
205 |
|
206 // ---------------------------------------------------------------------------- |
|
207 // MacroAnalyser::FindMacro |
|
208 // readParameters should be called so that first is called baseline command |
|
209 // and after that current command, otherwise it doesn't work |
|
210 // ---------------------------------------------------------------------------- |
|
211 // |
|
212 map<string, TChange<map<string, pair<pair<string, string>,string> > > >& MacroAnalyser::getChanged() |
|
213 { |
|
214 return iChanged; |
|
215 } |
|
216 |
|
217 // ---------------------------------------------------------------------------- |
|
218 // MacroAnalyser::getBaseDuplicates |
|
219 // ---------------------------------------------------------------------------- |
|
220 // |
|
221 map<string, vector<pair<string,string> > >& MacroAnalyser::getBaseDuplicates() |
|
222 { |
|
223 return iBaseDuplicates; |
|
224 } |
|
225 |
|
226 // ---------------------------------------------------------------------------- |
|
227 // MacroAnalyser::getCurrentDuplicates |
|
228 // ---------------------------------------------------------------------------- |
|
229 // |
|
230 map<string, vector<pair<string,string> > >& MacroAnalyser::getCurrentDuplicates() |
|
231 { |
|
232 return iCurrentDuplicates; |
|
233 } |
|
234 |
|
235 // ---------------------------------------------------------------------------- |
|
236 // MacroAnalyser::parseMacros |
|
237 // ---------------------------------------------------------------------------- |
|
238 // |
|
239 map<string, list<pair<pair<string, string>,string> > > MacroAnalyser::parseMacros(ifstream& aFile, vector<string>& bundlefiles, map<string, TChange<list<pair<string,string> > > >* aRemoved, bool aAddToRemoved) |
|
240 { |
|
241 // ret, is the file and related set of macros returned by the function |
|
242 map<string, list<pair<pair<string, string>,string> > > ret; |
|
243 vector<pair<string, string> > files; |
|
244 vector<string>::iterator bundlefile = bundlefiles.begin(); |
|
245 vector<string>::iterator bundleend = bundlefiles.end(); |
|
246 for(; bundlefile != bundleend; bundlefile++) |
|
247 { |
|
248 pair<string, string> bothcase(toLowerCaseWin(*bundlefile), *bundlefile); |
|
249 files.push_back(bothcase); |
|
250 } |
|
251 // Read macrofiles as lines |
|
252 string cline; |
|
253 string levelname = ""; |
|
254 bool isbundle = false; |
|
255 while((cline = getLine(aFile)) != KEmpty) |
|
256 { |
|
257 string line = cline; |
|
258 char tempNo[6]; |
|
259 string lineNo; |
|
260 unsigned int length = (unsigned int)line.length(); |
|
261 if (length > 6 && line.at(0) == '#' && line.at(1) == ' ') |
|
262 { // we may have found a file descriptor: '# xx "path/to/file.h"' or |
|
263 // '# xx "path/to/file.h" 1' or '# xx "path/to/file.h" 2' |
|
264 unsigned int index; |
|
265 int count = 0; |
|
266 for(index = 2; index < length; index++) |
|
267 { |
|
268 char ch = line.at(index); |
|
269 if (ch < '0' || ch > '9') |
|
270 break; |
|
271 else |
|
272 { |
|
273 tempNo[count] = ch; |
|
274 count++; |
|
275 } |
|
276 } |
|
277 tempNo[count] = '\0'; |
|
278 lineNo.copy(tempNo,strlen(tempNo)); |
|
279 index++; |
|
280 if (index < length) |
|
281 { |
|
282 unsigned int index2 = index + 1; |
|
283 for(; index2 < length; index2++) |
|
284 { |
|
285 char ch = line.at(index2); |
|
286 if (ch == '"') break; |
|
287 } |
|
288 if (length > index2 + 1) |
|
289 { |
|
290 levelname = line.substr(index + 1, index2 - index - 1); |
|
291 } else |
|
292 { |
|
293 levelname = line.substr(index + 1, length - index - 2); |
|
294 } |
|
295 string correctedname = ""; |
|
296 string::size_type start = 0; |
|
297 string::size_type pos = levelname.find_first_of("\\/"); |
|
298 while(pos != string::npos) |
|
299 { |
|
300 correctedname += levelname.substr(start, pos - start); |
|
301 correctedname += DIR_SEPARATOR; |
|
302 start = pos + 1; |
|
303 pos = levelname.find_first_of("\\/", start); |
|
304 } |
|
305 // found the levelname; filename |
|
306 correctedname += levelname.substr(start); |
|
307 levelname = toLowerCaseWin(correctedname); |
|
308 |
|
309 vector<pair<string, string> >::iterator begin = files.begin(); |
|
310 vector<pair<string, string> >::iterator end = files.end(); |
|
311 |
|
312 isbundle = false; |
|
313 for(; begin != end; begin++) |
|
314 { |
|
315 if (begin->first == levelname) |
|
316 { |
|
317 isbundle = true; |
|
318 levelname = begin->second; |
|
319 break; |
|
320 } |
|
321 } |
|
322 } |
|
323 } |
|
324 else if (isbundle == true && length > 8 && line.substr(0, 8) == "#define ") |
|
325 { // we found preprocessor directive #define |
|
326 pair<string,string> macro = FindMacro(line); |
|
327 // 'ret' contains the set of files and associated macros to be returned from function |
|
328 map<string, list<pair<pair<string, string>,string> > >::iterator found = ret.find(levelname); |
|
329 bool exist = false; |
|
330 if( found != ret.end()) |
|
331 { |
|
332 list< pair<pair<string, string>,string> >::iterator start = found->second.begin(); |
|
333 list< pair<pair<string, string>,string> >::iterator end = found->second.end(); |
|
334 |
|
335 // check if this macro is already defined, within this file(levelname) |
|
336 while(start != end) |
|
337 { |
|
338 if( macro.first == start->first.first ) |
|
339 exist = true; |
|
340 start++; |
|
341 } |
|
342 } |
|
343 // if macro not found, add it to the list of macros associated with the current file |
|
344 if( !exist ) |
|
345 { |
|
346 pair<pair<string,string>,string> tempVal(macro,tempNo); |
|
347 // if file already defined, only add the macro |
|
348 if (found != ret.end()) |
|
349 { |
|
350 found->second.push_back(tempVal); |
|
351 } |
|
352 // else add both filename and asssociated macro |
|
353 else |
|
354 { |
|
355 list<pair<pair<string, string>,string> > values; |
|
356 values.push_back(tempVal); |
|
357 pair<string, list<pair<pair<string, string>,string> > > newfile(levelname, values); |
|
358 ret.insert(newfile); |
|
359 } |
|
360 // perform the same test as above on aRemoved data structure |
|
361 // this will be used for finding any duplicate macro definitions |
|
362 if (aAddToRemoved == true) |
|
363 { |
|
364 pair<string,string> temp(macro.first,tempNo); |
|
365 map<string, TChange<list<pair<string,string> > > >::iterator found2 = aRemoved->find(levelname); |
|
366 if (found2 != aRemoved->end()) |
|
367 { |
|
368 found2->second.GetValue().push_back(temp); |
|
369 } else |
|
370 { |
|
371 list<pair<string,string> > values; |
|
372 values.push_back(temp); |
|
373 TChange<list<pair<string,string> > > tempvar(levelname, values); |
|
374 pair<string, TChange<list<pair<string,string> > > > newfile(levelname, tempvar); |
|
375 aRemoved->insert(newfile); |
|
376 } |
|
377 } |
|
378 } //if(!exist) |
|
379 } |
|
380 } |
|
381 return ret; |
|
382 } |
|
383 |
|
384 // ---------------------------------------------------------------------------- |
|
385 // MacroAnalyser::findDuplicates |
|
386 // ---------------------------------------------------------------------------- |
|
387 // |
|
388 bool MacroAnalyser::findDuplicates(const string& basefilename, const string& currentfilename, list<pair<pair<string, string>,string> >& aBaseline, list<pair<pair<string, string>,string> >& aCurrent, TChange<list<pair<string,string> > >& aRemovedList, map<string, vector<pair<string,string> > >& baselinedup, map<string, vector<pair<string,string> > >& currentdup) |
|
389 { |
|
390 bool ret = false; |
|
391 map<pair<string,string>, int> dups; |
|
392 list<pair<pair<string, string>,string> >::iterator begin = aBaseline.begin(); |
|
393 list<pair<pair<string, string>,string> >::iterator end = aBaseline.end(); |
|
394 bool found = false; |
|
395 while(begin != end) |
|
396 { |
|
397 found = false; |
|
398 list<pair<pair<string, string>,string> >::iterator duplicates = begin; |
|
399 duplicates++; |
|
400 string original = begin->first.first; |
|
401 pair<string,string> original1(original,begin->second); |
|
402 while(duplicates != end) |
|
403 { |
|
404 if (original == duplicates->first.first) |
|
405 { |
|
406 found = true; |
|
407 pair<pair<string,string>, int> tempvar(original1, 1); |
|
408 dups.insert(tempvar); |
|
409 duplicates = aBaseline.erase(duplicates); |
|
410 } else |
|
411 { |
|
412 duplicates++; |
|
413 } |
|
414 } |
|
415 if(found) |
|
416 { |
|
417 ret = true; |
|
418 aRemovedList.GetValue().remove(original1); |
|
419 begin = aBaseline.erase(begin); |
|
420 } |
|
421 begin++; |
|
422 } |
|
423 |
|
424 if (dups.size() != 0) |
|
425 { |
|
426 vector<pair<string,string> > values; |
|
427 values.reserve(dups.size()); |
|
428 map<pair<string,string>, int>::iterator dupsbegin = dups.begin(); |
|
429 map<pair<string,string>, int>::iterator dupsend = dups.end(); |
|
430 for(; dupsbegin != dupsend; dupsbegin++) |
|
431 { |
|
432 values.push_back(dupsbegin->first); |
|
433 } |
|
434 pair<string, vector<pair<string,string> > > tempvar(basefilename, values); |
|
435 baselinedup.insert(tempvar); |
|
436 } |
|
437 |
|
438 dups.clear(); |
|
439 begin = aCurrent.begin(); |
|
440 end = aCurrent.end(); |
|
441 while(begin != end) |
|
442 { |
|
443 found = false; |
|
444 list<pair<pair<string, string>,string> >::iterator duplicates = begin; |
|
445 duplicates++; |
|
446 string original = begin->first.first; |
|
447 pair<string,string> original1(original,begin->second); |
|
448 while(duplicates != end) |
|
449 { |
|
450 if (original == duplicates->first.first) |
|
451 { |
|
452 found = true; |
|
453 pair<pair<string,string>, int> tempvar(original1, 1); |
|
454 dups.insert(tempvar); |
|
455 duplicates = aCurrent.erase(duplicates); |
|
456 } else |
|
457 { |
|
458 duplicates++; |
|
459 } |
|
460 } |
|
461 if (found == true) |
|
462 { |
|
463 ret = true; |
|
464 begin = aCurrent.erase(begin); |
|
465 } else |
|
466 { |
|
467 begin++; |
|
468 } |
|
469 } |
|
470 |
|
471 if (dups.size() != 0) |
|
472 { |
|
473 vector<pair<string,string> > values; |
|
474 values.reserve(dups.size()); |
|
475 map<pair<string,string>, int>::iterator dupsbegin = dups.begin(); |
|
476 map<pair<string,string>, int>::iterator dupsend = dups.end(); |
|
477 for(; dupsbegin != dupsend; dupsbegin++) |
|
478 { |
|
479 string macroname = dupsbegin->first.first; |
|
480 pair<string,string> tempVal (macroname,dupsbegin->first.second); |
|
481 begin = aBaseline.begin(); |
|
482 end = aBaseline.end(); |
|
483 for(; begin != end; begin++) |
|
484 { // we have to remove all macros, which have duplicates in current, from baseline |
|
485 // so that there won't be unnecessary warnings of removed macros |
|
486 if (begin->first.first == macroname) |
|
487 { |
|
488 aBaseline.erase(begin); |
|
489 break; |
|
490 } |
|
491 } |
|
492 values.push_back(tempVal); |
|
493 } |
|
494 pair<string, vector<pair<string,string> > > tempvar(currentfilename, values); |
|
495 currentdup.insert(tempvar); |
|
496 } |
|
497 return ret; |
|
498 } |