1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (info@qt.nokia.com)
10 ** GNU Lesser General Public License Usage
12 ** This file may be used under the terms of the GNU Lesser General Public
13 ** License version 2.1 as published by the Free Software Foundation and
14 ** appearing in the file LICENSE.LGPL included in the packaging of this file.
15 ** Please review the following information to ensure the GNU Lesser General
16 ** Public License version 2.1 requirements will be met:
17 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
19 ** In addition, as a special exception, Nokia gives you certain additional
20 ** rights. These rights are described in the Nokia Qt LGPL Exception
21 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
25 ** Alternatively, this file may be used in accordance with the terms and
26 ** conditions contained in a signed written agreement between you and Nokia.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
31 **************************************************************************/
33 #include "parsemanager.h"
34 #include "cplusplus/CppDocument.h"
39 #include "TranslationUnit.h"
45 #include "cpptools/cppmodelmanager.h"
46 #include <QTextStream>
48 using namespace CppTools;
49 using namespace CppTools::Internal;
52 using namespace CPlusPlus;
54 //<------------------------------------------------------- Compare function for the internal structures
55 /**********************************
56 Compares function with function
57 with return type, function name
58 and their arguments and arguments
60 **********************************/
61 bool FUNCTIONITEM::isEqualTo(FUNCTIONITEM *cpfct, bool ignoreName/* = true*/)
64 return function->isEqualTo(cpfct->function, true);
65 return function->isEqualTo(cpfct->function);
68 /*****************************************************************
69 Compares two property regarding
70 of their function definition,
71 type definition, function arguments
74 Q_PROPERTY( ConnectionState state READ state NOTIFY stateChanged);
75 ******************************************************************/
76 bool PROPERTYITEM::isEqualTo(PROPERTYITEM *cpppt)
78 if (!ast->type_id || !cpppt->ast->type_id)
80 if (type != cpppt->type)
83 if (!ast->property_name || !ast->property_name->name || !ast->property_name->name->identifier())
85 QString thistypename = ast->property_name->name->identifier()->chars();
87 if (!cpppt->ast->property_name || !cpppt->ast->property_name->name || !cpppt->ast->property_name->name->identifier())
89 QString cppttypename = cpppt->ast->property_name->name->identifier()->chars();
90 if(thistypename != cppttypename)
93 if ((this->readAst == 0) != (cpppt->readAst == 0))
95 if((this->writeAst == 0) != (cpppt->writeAst == 0))
97 if((this->resetAst == 0) != (cpppt->resetAst == 0))
99 if((this->notifyAst == 0) != (cpppt->notifyAst == 0))
101 //check for read function
103 if(!this->readFct || !cpppt->readFct)
105 if(!this->readFct->isEqualTo(cpppt->readFct))
108 //check for write function
110 if(!this->writeFct || !cpppt->writeFct)
112 if(!this->writeFct->isEqualTo(cpppt->writeFct))
115 //check for reset function
117 if(!this->resetFct || !cpppt->resetFct)
119 if(!this->resetFct->isEqualTo(cpppt->resetFct))
122 //check for notify function
124 if(!this->notifyFct || !cpppt->notifyFct)
126 if(!this->notifyFct->isEqualTo(cpppt->notifyFct))
132 /*****************************************************************
133 Compares two enums regarding
134 of their values created by the getEnumValueStringList function.
135 *****************************************************************/
136 bool QENUMITEM::isEqualTo(QENUMITEM *cpenum)
138 if(this->values.count() != cpenum->values.count())
140 foreach(QString str, this->values){
141 if(!cpenum->values.contains(str))
147 /*****************************************************************
148 Compares two flags regarding
149 of their enum definitions and their
150 values created by the getEnumValueStringList function.
151 *****************************************************************/
152 bool QFLAGITEM::isEqualTo(QFLAGITEM *cpflag)
154 if(this->enumvalues.count() != cpflag->enumvalues.count())
156 foreach(QString str, this->enumvalues){
157 if(!cpflag->enumvalues.contains(str))
165 ParseManager::ParseManager()
166 : pCppPreprocessor(0)
171 ParseManager::~ParseManager()
174 delete pCppPreprocessor;
176 ::m_resultFile->close();
177 delete ::m_resultFile;
182 /**************************************
183 Function for setting the include
185 **************************************/
186 void ParseManager::setIncludePath(const QStringList &includePath)
188 m_includePaths = includePath;
191 /**************************************
192 public Function that starts the parsing
193 all of the files in the sourceFiles
195 **************************************/
196 void ParseManager::parse(const QStringList &sourceFiles)
199 if(pCppPreprocessor){
200 delete pCppPreprocessor;
201 pCppPreprocessor = 0;
204 if (! sourceFiles.isEmpty()) {
205 m_strHeaderFile = sourceFiles[0];
206 pCppPreprocessor = new CppTools::Internal::CppPreprocessor(QPointer<CPlusPlus::ParseManager>(this));
207 pCppPreprocessor->setIncludePaths(m_includePaths);
208 pCppPreprocessor->setFrameworkPaths(m_frameworkPaths);
209 parse(pCppPreprocessor, sourceFiles);
213 /*********************************************
214 private function that prepare the filelist
215 to parse and starts the parser.
216 *********************************************/
217 void ParseManager::parse(CppTools::Internal::CppPreprocessor *preproc,
218 const QStringList &files)
223 //check if file is C++ header file
225 foreach (const QString &file, files) {
226 const QFileInfo fileInfo(file);
227 QString ext = fileInfo.suffix();
228 if (ext.toLower() == "h")
229 headers.append(file);
232 foreach (const QString &file, files) {
233 preproc->snapshot.remove(file);
235 preproc->setTodo(headers);
236 QString conf = QLatin1String("<configuration>");
239 for (int i = 0; i < headers.size(); ++i) {
240 QString fileName = headers.at(i);
241 preproc->run(fileName);
245 //This function creates a class list for each class and its base classes in
246 //the header file that needs to be checked.
251 // Cl11 Cl12 Cl21 Cl22
253 //==> list[0] = {Cl1, Cl11, Cl12}
254 // list[1] = {Cl2, Cl21, Cl22}
256 QList<CLASSTREE*> ParseManager::CreateClassLists(bool isInterfaceHeader)
258 QList<CLASSTREE*>ret;
259 QList<CLASSLISTITEM*> classlist;
260 QList<CLASSLISTITEM*> allclasslist;
262 Trace("Following classes scaned for header file: " + m_strHeaderFile);
263 //Iteration over all parsed documents
264 if(getPreProcessor()){
265 for (Snapshot::const_iterator it = getPreProcessor()->snapshot.begin()
266 ; it != getPreProcessor()->snapshot.end(); ++it)
268 Document::Ptr doc = (*it);
270 QFileInfo fileinf(doc->fileName());
271 QFileInfo fileinf1(m_strHeaderFile);
272 //Get the Translated unit
273 Control* ctrl = doc->control();
274 TranslationUnit* trlUnit = ctrl->translationUnit();
275 AST* pAst = trlUnit->ast();
276 TranslationUnitAST *ptrAst = 0;
277 if(pAst && (ptrAst = pAst->asTranslationUnit())){
278 //iteration over all translated declaration in this document
279 for (DeclarationListAST *pDecllist = ptrAst->declaration_list; pDecllist; pDecllist = pDecllist->next) {
280 if(pDecllist->value){
281 SimpleDeclarationAST *pSimpleDec = pDecllist->value->asSimpleDeclaration();
283 //Iteration over class specifier
284 for (SpecifierListAST *pSimpleDecDecllist = pSimpleDec->decl_specifier_list; pSimpleDecDecllist; pSimpleDecDecllist = pSimpleDecDecllist->next) {
285 ClassSpecifierAST * pclassspec = pSimpleDecDecllist->value->asClassSpecifier();
287 CLASSLISTITEM* item = new CLASSLISTITEM();
288 item->classspec = pclassspec;
289 item->trlUnit = trlUnit;
290 allclasslist.push_back(item);
291 QString classname = item->trlUnit->spell(item->classspec->name->firstToken());
292 Trace("- " + classname + " class scaned");
294 //We found a class that is defined in the header file that needs to be checked
295 if(fileinf.fileName().toLower() == fileinf1.fileName().toLower()){
296 CLASSTREE* cltree = new CLASSTREE();
297 cltree->highestlevelclass = item;
298 cltree->classlist.push_back(item);
299 ret.push_back(cltree);
310 //after we search for the classes we need to search for the baseclasses
311 Trace("Following classes found in Header file: " + m_strHeaderFile);
312 foreach(CLASSTREE *cltree, ret){
313 QString classname = cltree->highestlevelclass->trlUnit->spell(cltree->highestlevelclass->classspec->name->firstToken());
314 Trace("- " + classname + " class found");
315 QList<CLASSLISTITEM*> baseclasslist;
316 getBaseClasses(cltree->highestlevelclass, baseclasslist, allclasslist, 0, isInterfaceHeader);
317 cltree->classlist.append(baseclasslist);
322 /********************************************
323 Gets all the baseclass from a class and
324 add those base classes into the baseclasslist
325 ********************************************/
326 void ParseManager::getBaseClasses(const CLASSLISTITEM* pclass
327 , QList<CLASSLISTITEM*> &baseclasslist
328 , const QList<CLASSLISTITEM*> &allclasslist
330 , bool isInterfaceHeader)
332 //iteration over the base_clause_list of the current class
333 QString levelmarker = " ";
334 for(int i = 0; i < level; i++)
336 levelmarker += "|- ";
337 QList<CLASSLISTITEM*>child;
339 for(BaseSpecifierListAST *pBaseSpecList = pclass->classspec->base_clause_list; pBaseSpecList; pBaseSpecList = pBaseSpecList->next)
341 BaseSpecifierAST *pBaseSpec = pBaseSpecList->value;
343 foreach(CLASSLISTITEM* pclspec, allclasslist)
345 if(pclspec->classspec->symbol->name()
346 && pBaseSpec->symbol->name()
347 && pclspec->classspec->symbol->name()->isEqualTo(pBaseSpec->symbol->name()))
349 child.push_back(pclspec);
350 baseclasslist.push_back(pclspec);
351 QString classname = pclspec->trlUnit->spell(pclspec->classspec->name->firstToken());
352 Trace(levelmarker + classname + " class found");
357 if(!found && pBaseSpec->name){
358 QString classname = pclass->trlUnit->spell(pBaseSpec->name->firstToken());
359 if(isInterfaceHeader)
360 Trace(levelmarker + classname + " class not found! Interface classes should not be inherited from Qt Objects!");
362 Trace(levelmarker + classname + " class not found!");
365 //call the function recursive because all the basclasses can have other base classes
366 foreach(CLASSLISTITEM* pchclass, child){
367 getBaseClasses(pchclass, baseclasslist, allclasslist, ++level, isInterfaceHeader);
371 /**************************************************
372 This function finds and creates all Elements wich
373 are significant for MetaDatas.
374 Those element will be added in the aparameter
376 **************************************************/
377 void ParseManager::getElements(QList<FUNCTIONITEM*> &functionlist
378 , QList<PROPERTYITEM*> &propertylist
379 , QList<QENUMITEM*> &qenumlist
380 , QList<ENUMITEM*> &enumlist
381 , QList<QFLAGITEM*> &qflaglist
382 , QList<QDECLAREFLAGSITEM*> &qdeclareflaglist
383 , const QList<CLASSLISTITEM*> classitems
384 , const CLASSLISTITEM* highestlevelclass)
386 foreach(CLASSLISTITEM* classitem, classitems){
387 QString classname = "";
388 if(classitem->classspec->name)
389 classname = classitem->trlUnit->spell(classitem->classspec->name->firstToken());
390 for (DeclarationListAST *pmemberlist = classitem->classspec->member_specifier_list; pmemberlist; pmemberlist = pmemberlist->next) {
394 if (FunctionDefinitionAST *pfctdef = pmemberlist->value->asFunctionDefinition()){
395 FUNCTIONITEM* item = new FUNCTIONITEM;
396 item->trlUnit = classitem->trlUnit;
397 item->function = pfctdef->symbol;
398 item->classAst = classitem->classspec;
399 item->highestlevelclass = highestlevelclass;
400 functionlist.push_back(item);
401 if(isMetaObjFunction(item))
402 Trace(" - " + getTraceFuntionString(item, classname) + " found");
405 SimpleDeclarationAST *pdecl = pmemberlist->value->asSimpleDeclaration();
407 for(List<Symbol*>* decllist = pdecl->symbols; decllist; decllist = decllist->next)
409 Function* pfct = decllist->value->type()->asFunctionType();
411 FUNCTIONITEM* item = new FUNCTIONITEM();
412 item->trlUnit = classitem->trlUnit;
413 item->function = pfct;
414 item->classAst = classitem->classspec;
415 item->highestlevelclass = highestlevelclass;
416 functionlist.push_back(item);
417 if(isMetaObjFunction(item))
418 Trace(" - " + getTraceFuntionString(item, classname) + " found");
424 for(List<SpecifierAST*>* decllist = pdecl->decl_specifier_list; decllist; decllist = decllist->next)
426 EnumSpecifierAST * penum = decllist->value->asEnumSpecifier();
428 ENUMITEM* item = new ENUMITEM();
430 item->highestlevelclass = highestlevelclass;
431 item->trlUnit = classitem->trlUnit;
432 enumlist.push_back(item);
440 if(QtPropertyDeclarationAST *ppdecl = pmemberlist->value->asQtPropertyDeclaration()) {
441 propertylist.push_back(PROPERTYITEM::create(ppdecl, highestlevelclass));
442 if (ppdecl->property_name && ppdecl->property_name->name && ppdecl->property_name->name->identifier()) {
443 Trace(" - Q_PROPERTY: " + QLatin1String(ppdecl->property_name->name->identifier()->chars()) + " found");
449 if (QtEnumDeclarationAST *pqenum = pmemberlist->value->asQtEnumDeclaration()) {
450 for (NameListAST *plist = pqenum->enumerator_list; plist; plist = plist->next) {
451 QENUMITEM* item = new QENUMITEM;
452 item->name = plist->value->name->identifier()->chars();
453 item->highestlevelclass = highestlevelclass;
454 qenumlist.push_back(item);
455 Trace(" - Q_ENUM: " + classname + "::" + item->name + " found");
462 if (QtFlagsDeclarationAST *pqflags = pmemberlist->value->asQtFlagsDeclaration()){
463 for (NameListAST *plist = pqflags->flag_enums_list; plist; plist = plist->next) {
464 QFLAGITEM* item = new QFLAGITEM;
465 item->name = plist->value->name;
466 item->highestlevelclass = highestlevelclass;
467 qflaglist.push_back(item);
468 Trace(" - Q_FLAGS: " + classname + "::" + item->name->identifier()->chars() + " found");
472 /*The code for Q_DECLARE_FLAGS was wrong. It's optional, and only does a typedef.
473 That means, if you do the typedef yourself and not use Q_DECLARE_FLAGS, that *is* valid.
474 Meaning, if one would want to do a check like the ones in this app, one has to check the defined types in the class scope.*/
479 QtDeclareFlagsDeclarationAST *pqdeclflags = pmemberlist->value->asQDeclareFlagsDeclarationAST();
481 QDECLAREFLAGSITEM* item = new QDECLAREFLAGSITEM();
482 item->ast = pqdeclflags;
483 item->highestlevelclass = highestlevelclass;
484 item->trlUnit = classitem->trlUnit;
485 qdeclareflaglist.push_back(item);
496 /*********************************************
497 Function that starts the comare between the
498 parser result and their metadata content.
499 *********************************************/
500 bool ParseManager::checkAllMetadatas(ParseManager* pInterfaceParserManager, QString resultfile)
505 if(resultfile != "" && ::m_resultFile == 0){
506 ::m_resultFile = new QFile(resultfile);
507 if (!::m_resultFile->open(QFile::WriteOnly | QFile::Truncate)) {
508 delete ::m_resultFile;
513 /************************************************
514 Get all elements from the interface header file
515 ************************************************/
516 Trace("### Get all elements from the interface header file ###");
517 QList<CLASSTREE*> ilookuplist = pInterfaceParserManager->CreateClassLists(true);
518 QList<QList<FUNCTIONITEM*> > ifunctionslookuplist;
519 QList<QList<PROPERTYITEM*> > ipropertieslookuplist;
520 QList<QList<QENUMITEM*> > iqenumlookuplist;
521 QList<QList<ENUMITEM*> > ienumlookuplist;
522 QList<QList<QFLAGITEM*> > iqflaglookuplist;
523 QList<QList<QDECLAREFLAGSITEM*> > iqdeclareflaglookuplist;
524 Trace("Following MetaData found:");
525 foreach(CLASSTREE* iclasstree, ilookuplist){
526 QList<FUNCTIONITEM*>functionlist;
527 QList<PROPERTYITEM*>propertylist;
528 QList<QENUMITEM*>qenumlist;
529 QList<ENUMITEM*>enumlist;
530 QList<QFLAGITEM*> qflaglist;
531 QList<QDECLAREFLAGSITEM*> qdeclareflag;
532 getElements(functionlist
538 , iclasstree->classlist
539 , iclasstree->highestlevelclass);
540 if(functionlist.size() > 0)
541 ifunctionslookuplist.append(functionlist);
542 if(propertylist.size() > 0)
543 ipropertieslookuplist.append(propertylist);
544 if(qenumlist.size() > 0)
545 iqenumlookuplist.append(qenumlist);
546 if(enumlist.size() > 0)
547 ienumlookuplist.append(enumlist);
548 if(qflaglist.size() > 0)
549 iqflaglookuplist.append(qflaglist);
550 if(qdeclareflag.size() > 0)
551 iqdeclareflaglookuplist.append(qdeclareflag);
554 /************************************************
555 Get all elements from the compare header file
556 ************************************************/
558 Trace("### Get all elements from the compare header file ###");
559 QList<CLASSTREE*> lookuplist = CreateClassLists(false);
560 QList<QList<FUNCTIONITEM*> > functionslookuplist;
561 QList<QList<PROPERTYITEM*> > propertieslookuplist;
562 QList<QList<QENUMITEM*> > qenumlookuplist;
563 QList<QList<ENUMITEM*> > enumlookuplist;
564 QList<QList<QFLAGITEM*> > qflaglookuplist;
565 QList<QList<QDECLAREFLAGSITEM*> > qdeclareflaglookuplist;
566 Trace("Following MetaData found:");
567 foreach(CLASSTREE* classtree, lookuplist){
568 QList<FUNCTIONITEM*>functionlist;
569 QList<PROPERTYITEM*>propertylist;
570 QList<QENUMITEM*>qenumlist;
571 QList<ENUMITEM*>enumlist;
572 QList<QFLAGITEM*> qflaglist;
573 QList<QDECLAREFLAGSITEM*> qdeclareflag;
574 getElements(functionlist
580 , classtree->classlist
581 , classtree->highestlevelclass);
582 if(functionlist.size() > 0)
583 functionslookuplist.append(functionlist);
584 if(propertylist.size() > 0)
585 propertieslookuplist.append(propertylist);
586 if(qenumlist.size() > 0)
587 qenumlookuplist.append(qenumlist);
588 if(enumlist.size() > 0)
589 enumlookuplist.append(enumlist);
590 if(qflaglist.size() > 0)
591 qflaglookuplist.append(qflaglist);
592 if(qdeclareflag.size() > 0)
593 qdeclareflaglookuplist.append(qdeclareflag);
597 Trace("### Result: ###");
598 /******************************
600 ******************************/
601 Trace("Compare all interface MetaData functions:");
602 QList<FUNCTIONITEM*> missingifcts = checkMetadataFunctions(functionslookuplist, ifunctionslookuplist);
603 if(missingifcts.size() > 0){
604 foreach(FUNCTIONITEM* ifct, missingifcts){
605 m_errormsgs.append(getErrorMessage(ifct));
614 /******************************
616 ******************************/
617 Trace("Compare all interface MetaData properties:");
618 QList<PROPERTYITEM*> missingippts = checkMetadataProperties(propertieslookuplist, functionslookuplist, ipropertieslookuplist, ifunctionslookuplist);
619 if(missingippts.size() > 0){
620 foreach(PROPERTYITEM* ippt, missingippts){
621 m_errormsgs.append(getErrorMessage(ippt));
630 /******************************
632 ******************************/
633 Trace("Compare all interface MetaData enums:");
634 QList<QENUMITEM*> missingiqenums = checkMetadataEnums(qenumlookuplist, enumlookuplist, iqenumlookuplist, ienumlookuplist);
635 if(missingiqenums.size() > 0){
636 foreach(QENUMITEM* ienum, missingiqenums){
637 m_errormsgs.append(getErrorMessage(ienum));
646 /******************************
648 ******************************/
649 Trace("Compare all interface MetaData flags:");
650 QList<QFLAGITEM*> missingiqflags = checkMetadataFlags(qflaglookuplist, qdeclareflaglookuplist, enumlookuplist
651 , iqflaglookuplist, iqdeclareflaglookuplist, ienumlookuplist);
652 if(missingiqflags.size() > 0){
653 foreach(QFLAGITEM* iflags, missingiqflags){
654 m_errormsgs.append(getErrorMessage(iflags));
663 /******************************
665 ******************************/
667 Trace("### summary ###");
668 if(m_errormsgs.size() > 0){
669 Trace("- Folowing interface items are missing:");
670 foreach(QString msg, m_errormsgs)
674 Trace("Interface is full defined.");
676 //now delet all Classitems
677 foreach(CLASSTREE* l, ilookuplist){
678 l->classlist.clear();
680 foreach(CLASSTREE* l, lookuplist){
681 l->classlist.clear();
683 //delete all functionitems
684 foreach(QList<FUNCTIONITEM*>l, ifunctionslookuplist){
687 foreach(QList<FUNCTIONITEM*>l, functionslookuplist){
690 //delete all properties
691 foreach(QList<PROPERTYITEM*>l, ipropertieslookuplist){
694 foreach(QList<PROPERTYITEM*>l, propertieslookuplist){
698 foreach(QList<QENUMITEM*>l, iqenumlookuplist){
701 foreach(QList<QENUMITEM*>l, iqenumlookuplist){
705 foreach(QList<ENUMITEM*>l, ienumlookuplist){
708 foreach(QList<ENUMITEM*>l, enumlookuplist){
712 foreach(QList<QFLAGITEM*>l, iqflaglookuplist){
715 foreach(QList<QFLAGITEM*>l, qflaglookuplist){
718 //delete all qdeclareflags
719 foreach(QList<QDECLAREFLAGSITEM*>l, iqdeclareflaglookuplist){
722 foreach(QList<QDECLAREFLAGSITEM*>l, qdeclareflaglookuplist){
729 //<------------------------------------------------------- Start of MetaData functions
730 /***********************************
731 Function that checks all functions
732 which will occur in the MetaData
733 ***********************************/
734 QList<FUNCTIONITEM*> ParseManager::checkMetadataFunctions(const QList<QList<FUNCTIONITEM*> > &classfctlist, const QList<QList<FUNCTIONITEM*> > &iclassfctlist)
736 QList<FUNCTIONITEM*> missingifcts;
737 //Compare each function from interface with function from header (incl. baseclass functions)
738 QList<FUNCTIONITEM*> ifcts;
739 foreach(QList<FUNCTIONITEM*>ifunctionlist, iclassfctlist){
741 //check if one header class contains all function from one interface header class
742 if(classfctlist.count() > 0){
743 foreach(QList<FUNCTIONITEM*>functionlist, classfctlist){
744 QList<FUNCTIONITEM*> tmpl = containsAllMetadataFunction(functionlist, ifunctionlist);
745 if(tmpl.size() == 0){
754 foreach(FUNCTIONITEM *pfct, ifunctionlist)
755 pfct->classWichIsNotFound << "<all classes>";
756 ifcts.append(ifunctionlist);
758 missingifcts.append(ifcts);
763 /*********************************************
764 Helper function to check if a function will
765 occure in the MetaData.
766 *********************************************/
767 bool ParseManager::isMetaObjFunction(FUNCTIONITEM* fct)
769 if(fct->function->isInvokable()
770 || fct->function->isSignal()
771 || fct->function->isSlot())
776 /****************************************************
777 Check if all function from iclassfctlist are defined
778 in the classfctlist as well.
779 It will return all the function they are missing.
780 ****************************************************/
781 QList<FUNCTIONITEM*> ParseManager::containsAllMetadataFunction(const QList<FUNCTIONITEM*> &classfctlist, const QList<FUNCTIONITEM*> &iclassfctlist)
783 QList<FUNCTIONITEM*> ret;
784 foreach(FUNCTIONITEM* ifct, iclassfctlist){
785 if(isMetaObjFunction(ifct)){
787 QStringList missingimplinclasses;
788 ClassSpecifierAST* clspec = 0;
789 QString classname = "";
790 foreach(FUNCTIONITEM* fct, classfctlist){
791 if(clspec != fct->highestlevelclass->classspec){
792 clspec = fct->highestlevelclass->classspec;
794 unsigned int firsttoken = clspec->name->firstToken();
795 classname += fct->trlUnit->spell(firsttoken);
796 if(missingimplinclasses.indexOf(classname) < 0)
797 missingimplinclasses.push_back(classname);
799 if(fct->isEqualTo(ifct, false)){
801 missingimplinclasses.clear();
802 Trace("- " + getTraceFuntionString(fct, classname) + " implemented");
807 ifct->classWichIsNotFound.append(missingimplinclasses);
809 QString classname = ifct->trlUnit->spell(ifct->highestlevelclass->classspec->name->firstToken());
810 Trace("- " + getTraceFuntionString(ifct, classname) + " not implemented!");
817 /************************************
818 Function that gives back an error
819 string for a MetaData function
821 ************************************/
822 QStringList ParseManager::getErrorMessage(FUNCTIONITEM* fct)
825 QString fctstring = "";
826 QString fcttype = "";
828 foreach(QString classname, fct->classWichIsNotFound){
830 QTextStream out(&tmp);
833 fctstring = classname;
836 unsigned int token = fct->function->sourceLocation() - 1;
837 while(fct->trlUnit->tokenAt(token).isNot(T_EOF_SYMBOL)){
838 fctstring += fct->trlUnit->tokenAt(token).spell();
839 if(*fct->trlUnit->tokenAt(token).spell() == ')')
845 Function* pfct = fct->function;
848 //Check for private, protected and public
851 if(pfct->isProtected())
852 fcttype = "protected ";
853 if(pfct->isPrivate())
854 fcttype = "private ";
856 if(pfct->isVirtual())
857 fcttype += "virtual ";
858 if(pfct->isPureVirtual())
859 fcttype += "pure virtual ";
862 fcttype += "Signal ";
866 fcttype += "Normal ";
867 if(pfct->isInvokable())
868 fcttype += "Invokable ";
870 out << fcttype << fctstring;
877 //<------------------------------------------------------- Start of Q_PROPERTY checks
878 /***********************************
879 Function that checks all Property
880 which will occur in the MetaData
881 ***********************************/
882 QList<PROPERTYITEM*> ParseManager::checkMetadataProperties(const QList<QList<PROPERTYITEM*> > &classproplist
883 , const QList<QList<FUNCTIONITEM*> > &classfctlist
884 , const QList<QList<PROPERTYITEM*> > &iclassproplist
885 , const QList<QList<FUNCTIONITEM*> > &iclassfctlist)
887 QList<PROPERTYITEM*> missingiprops;
888 //assign the property functions
889 foreach(QList<PROPERTYITEM*>proplist, classproplist){
890 foreach(PROPERTYITEM* prop, proplist){
891 assignPropertyFunctions(prop, classfctlist);
895 foreach(QList<PROPERTYITEM*>proplist, iclassproplist){
896 foreach(PROPERTYITEM* prop, proplist){
897 assignPropertyFunctions(prop, iclassfctlist);
901 //Compare each qproperty from interface with qproperty from header (incl. baseclass functions)
902 QList<PROPERTYITEM*> ippts;
903 foreach(QList<PROPERTYITEM*>ipropertylist, iclassproplist){
905 //check if one header class contains all function from one interface header class
906 if(classproplist.count() > 0){
907 foreach(QList<PROPERTYITEM*>propertylist, classproplist){
908 QList<PROPERTYITEM*> tmpl = containsAllPropertyFunction(propertylist, ipropertylist);
916 foreach(PROPERTYITEM *pprop, ipropertylist){
917 pprop->classWichIsNotFound << "<all classes>";
918 QString name = pprop->ast->property_name->name->identifier()->chars();
919 Trace("- Property: <all classes>::" + name + " not found!");
921 ippts.append(ipropertylist);
923 missingiprops.append(ippts);
925 return missingiprops;
928 static QString findName(ExpressionAST *ast)
930 // The "old" icheck code assumed that functions were only a single identifier, so I'll assume the same:
931 if (NameAST *nameAST = ast->asName())
932 return nameAST->name->identifier()->chars();
937 /**************************************
938 Function that resolves the dependensies
940 and thier READ, WRITE, NOTIFY and RESET
942 ***************************************/
943 void ParseManager::assignPropertyFunctions(PROPERTYITEM* prop, const QList<QList<FUNCTIONITEM*> > &fctlookuplist)
945 //get the name of the needed functions
947 QString writefctname;
948 QString resetfctname;
949 QString notifyfctname;
953 readfctname = findName(prop->readAst);
957 writefctname = findName(prop->writeAst);
961 resetfctname = findName(prop->resetAst);
965 notifyfctname = findName(prop->notifyAst);
968 //Now iterate over all function to find all functions wich are defined in the Q_PROPERTY macro
970 prop->foundalldefinedfct = false;
971 foreach(QList<FUNCTIONITEM*> fctlist, fctlookuplist){
972 foreach(FUNCTIONITEM* pfct, fctlist){
973 QString fctname = pfct->trlUnit->spell(pfct->function->sourceLocation());
974 //check the function type against the property type
975 FullySpecifiedType retTy = pfct->function->returnType();
977 if (!fctname.isEmpty() && retTy.isValid()) {
978 if(prop->readAst && fctname == readfctname){
979 if (prop->type != retTy)
981 prop->readFct = pfct;
984 if(prop->writeAst && fctname == writefctname){
985 prop->writeFct = pfct;
988 if(prop->resetAst && fctname == resetfctname){
989 prop->resetFct = pfct;
992 if(prop->notifyAst && fctname == notifyfctname){
993 prop->notifyFct = pfct;
997 //a flag that indicates if a function was missing
998 prop->foundalldefinedfct = true;
1007 /**************************************
1008 Function that checks if all functions
1009 dependencies in Q_PROPERTY have the
1010 same arguments and retunr value.
1011 ***************************************/
1012 QList<PROPERTYITEM*> ParseManager::containsAllPropertyFunction(const QList<PROPERTYITEM*> &classproplist, const QList<PROPERTYITEM*> &iclassproplist)
1014 QList<PROPERTYITEM*> ret;
1015 foreach(PROPERTYITEM* ipropt, iclassproplist){
1016 if(ipropt->foundalldefinedfct){
1018 QStringList missingimplinclasses;
1019 ClassSpecifierAST* clspec = 0;
1020 QString classname = "";
1021 foreach(PROPERTYITEM* propt, classproplist){
1022 if(clspec != propt->highestlevelclass->classspec){
1023 clspec = propt->highestlevelclass->classspec;
1025 unsigned int firsttoken = clspec->name->firstToken();
1026 classname += propt->trlUnit->spell(firsttoken);
1027 if(missingimplinclasses.indexOf(classname) < 0)
1028 missingimplinclasses.push_back(classname);
1030 if(propt->isEqualTo(ipropt)){
1032 missingimplinclasses.clear();
1033 Trace("- Property: " + classname + "::" + propt->ast->property_name->name->identifier()->chars() + " found");
1038 ipropt->classWichIsNotFound.append(missingimplinclasses);
1039 ret.push_back(ipropt);
1040 QString classname = ipropt->trlUnit->spell(ipropt->highestlevelclass->classspec->name->firstToken());
1041 Trace("- Property: " + classname + "::" + ipropt->ast->property_name->name->identifier()->chars() + " not found!");
1045 QString classname = ipropt->trlUnit->spell(ipropt->highestlevelclass->classspec->name->firstToken());
1047 QString proptype = oo(ipropt->type);
1048 Trace("- Property: " + classname + "::" + proptype + " functions are missing!");
1049 ret.push_back(ipropt);
1055 /************************************
1056 Function that gives back an error
1057 string for a Q_PROPERTY mismatch.
1058 ************************************/
1059 QStringList ParseManager::getErrorMessage(PROPERTYITEM* ppt)
1062 QString pptstring = "";
1064 if(!ppt->foundalldefinedfct)
1067 QTextStream out(&tmp);
1069 unsigned int firsttoken = ppt->highestlevelclass->classspec->name->firstToken();
1070 unsigned int lasttoken = ppt->highestlevelclass->classspec->name->lastToken();
1071 for(unsigned int i = firsttoken; i < lasttoken; i++){
1072 out << ppt->trlUnit->spell(i);
1075 firsttoken = ppt->ast->firstToken();
1076 lasttoken = ppt->ast->lastToken();
1077 for(unsigned int i = firsttoken; i <= lasttoken; i++){
1078 out << ppt->trlUnit->spell(i) << " ";
1080 out << endl << " -";
1081 if(ppt->readAst && !ppt->readFct)
1083 if(ppt->writeAst && !ppt->writeFct)
1085 if(ppt->resetAst && !ppt->resetFct)
1087 if(ppt->notifyAst && !ppt->notifyFct)
1089 out << "functions missing." << endl;
1092 for(int i = 0; i < ppt->classWichIsNotFound.size(); i++){
1094 QTextStream out(&tmp);
1096 pptstring = ppt->classWichIsNotFound[i];
1099 unsigned int firsttoken = ppt->ast->firstToken();
1100 unsigned int lasttoken = ppt->ast->lastToken();
1101 for(unsigned int i = firsttoken; i <= lasttoken; i++){
1102 pptstring += ppt->trlUnit->spell(i);
1114 //<------------------------------------------------------- Start of Q_ENUMS checks
1115 /***********************************
1116 Function that checks all enums
1117 which will occur in the MetaData
1118 ***********************************/
1119 QList<QENUMITEM*> ParseManager::checkMetadataEnums(const QList<QList<QENUMITEM*> > &classqenumlist
1120 , const QList<QList<ENUMITEM*> > &classenumlist
1121 , const QList<QList<QENUMITEM*> > &iclassqenumlist
1122 , const QList<QList<ENUMITEM*> > &iclassenumlist)
1124 QList<QENUMITEM*> missingiqenums;
1125 //assign the property functions
1126 foreach(QList<QENUMITEM*>qenumlist, classqenumlist){
1127 foreach(QENUMITEM* qenum, qenumlist){
1128 assignEnumValues(qenum, classenumlist);
1131 foreach(QList<QENUMITEM*>qenumlist, iclassqenumlist){
1132 foreach(QENUMITEM* qenum, qenumlist){
1133 assignEnumValues(qenum, iclassenumlist);
1137 //Compare each qenum from interface with qenum from header (incl. baseclass functions)
1138 QList<QENUMITEM*> iqenums;
1139 foreach(QList<QENUMITEM*>iqenumlist, iclassqenumlist){
1141 //check if one header class contains all function from one interface header class
1142 if(classqenumlist.count() > 0){
1143 foreach(QList<QENUMITEM*>qenumlist, classqenumlist){
1144 QList<QENUMITEM*> tmpl = containsAllEnums(qenumlist, iqenumlist);
1145 if(tmpl.size() == 0)
1148 iqenums.append(tmpl);
1153 foreach(QENUMITEM *qenum, iqenumlist){
1154 qenum->classWichIsNotFound << "<all classes>";
1155 Trace("- Enum: <all classes>::" + qenum->name + " not found!");
1157 iqenums.append(iqenumlist);
1159 missingiqenums.append(iqenums);
1162 return missingiqenums;
1165 /*********************************************
1166 Helper function which creates a string out of
1167 an enumerator including its values.
1168 *********************************************/
1169 QStringList ParseManager::getEnumValueStringList(ENUMITEM *penum, QString mappedenumname/* = ""*/)
1172 EnumSpecifierAST *penumsec = penum->ast;
1173 QString enumname = penum->trlUnit->spell(penumsec->name->firstToken());
1175 //now iterrate over all enumitems and create a string like following:
1176 //EnumName.EnumItemName.Value
1177 //ConnectionState.disconnected.0
1178 for (EnumeratorListAST *plist = penum->ast->enumerator_list; plist; plist = plist->next) {
1179 QString value = enumname;
1180 if(mappedenumname.size() > 0)
1181 value = mappedenumname;
1183 value += penum->trlUnit->spell(plist->value->identifier_token);
1185 if(plist->value->equal_token > 0 && plist->value->expression){
1186 QString v = penum->trlUnit->spell(plist->value->expression->firstToken());
1188 int newval = enumvalue;
1189 if(v.indexOf("0x") >= 0)
1190 newval = v.toInt(&ch, 16);
1192 newval = v.toInt(&ch, 10);
1196 value += QString::number(enumvalue);
1198 // now add this enumitem string in the VALUE list
1204 /**************************************
1205 Function that resolves the dependensies
1206 between Q_ENUMS and enums.
1207 ***************************************/
1208 void ParseManager::assignEnumValues(QENUMITEM* qenum, const QList<QList<ENUMITEM*> > &enumlookuplist)
1210 //iterate over all enums and find the one with the same name like enumname
1212 foreach (QList<ENUMITEM*> penumlist, enumlookuplist) {
1213 foreach(ENUMITEM *penum, penumlist){
1214 EnumSpecifierAST *penumsec = penum->ast;
1215 QString enumname1 = penum->trlUnit->spell(penumsec->name->firstToken());
1216 if(qenum->name == enumname1){
1217 qenum->values << getEnumValueStringList(penum);
1223 qenum->foundallenums = false;
1227 /***********************************
1228 Function that checkt if the Q_ENUMS
1229 are completed defined and if the
1230 Enum values are the same.
1231 ***********************************/
1232 QList<QENUMITEM*> ParseManager::containsAllEnums(const QList<QENUMITEM*> &classqenumlist, const QList<QENUMITEM*> &iclassqenumlist)
1236 QList<QENUMITEM*> ret;
1237 foreach(QENUMITEM* iqenum, iclassqenumlist){
1239 QStringList missingimplinclasses;
1240 ClassSpecifierAST* clspec = 0;
1241 QString classname = "";
1242 foreach(QENUMITEM* qenum, classqenumlist){
1243 if(clspec != qenum->highestlevelclass->classspec){
1244 clspec = qenum->highestlevelclass->classspec;
1246 classname += oo(clspec->symbol);
1247 if(missingimplinclasses.indexOf(classname) < 0)
1248 missingimplinclasses.push_back(classname);
1250 if(qenum->isEqualTo(iqenum)){
1252 missingimplinclasses.clear();
1253 Trace("- Enum: " + classname + "::" + qenum->name + " found");
1258 iqenum->classWichIsNotFound.append(missingimplinclasses);
1259 ret.push_back(iqenum);
1260 QString classname = oo(iqenum->highestlevelclass->classspec->symbol);
1261 Trace("- Enum: " + classname + "::" + iqenum->name + " not found!");
1267 /************************************
1268 Function that gives back an error
1269 string for a Q_ENUMS mismatch.
1270 ************************************/
1271 QStringList ParseManager::getErrorMessage(QENUMITEM* qenum)
1276 if(!qenum->foundallenums)
1279 QTextStream out(&tmp);
1281 out << oo(qenum->highestlevelclass->classspec->symbol);
1282 out << "::Q_ENUMS " << qenum->name << " enum missing.";
1286 for (int i = 0; i < qenum->classWichIsNotFound.size(); i++){
1288 QTextStream out(&tmp);
1290 out << qenum->classWichIsNotFound[i] << "::Q_ENUMS "
1298 //<------------------------------------------------------- Start of Q_FLAGS checks
1299 /***********************************
1300 Function that checks all flags
1301 which will occur in the MetaData
1302 ***********************************/
1303 QList<QFLAGITEM*> ParseManager::checkMetadataFlags(const QList<QList<QFLAGITEM*> > &classqflaglist
1304 , const QList<QList<QDECLAREFLAGSITEM*> > &classqdeclareflaglist
1305 , const QList<QList<ENUMITEM*> > &classenumlist
1306 , const QList<QList<QFLAGITEM*> > &iclassqflaglist
1307 , const QList<QList<QDECLAREFLAGSITEM*> > &iclassqdeclareflaglist
1308 , const QList<QList<ENUMITEM*> > &iclassenumlist)
1310 QList<QFLAGITEM*> missingqflags;
1311 //assign the enums to the flags
1312 foreach(QList<QFLAGITEM*>qflaglist, classqflaglist){
1313 foreach(QFLAGITEM* qflag, qflaglist){
1314 assignFlagValues(qflag, classqdeclareflaglist, classenumlist);
1317 foreach(QList<QFLAGITEM*>qflaglist, iclassqflaglist){
1318 foreach(QFLAGITEM* qflag, qflaglist){
1319 assignFlagValues(qflag, iclassqdeclareflaglist, iclassenumlist);
1323 //Compare each qenum from interface with qenum from header (incl. baseclass functions)
1324 QList<QFLAGITEM*> iqflags;
1325 foreach(QList<QFLAGITEM*>iqflaglist, iclassqflaglist){
1327 //check if one header class contains all function from one interface header class
1328 if(classqflaglist.count() >0){
1329 foreach(QList<QFLAGITEM*>qflaglist, classqflaglist){
1330 QList<QFLAGITEM*> tmpl = containsAllFlags(qflaglist, iqflaglist);
1331 if(tmpl.size() == 0)
1334 iqflags.append(tmpl);
1339 foreach(QFLAGITEM *pflag, iqflaglist){
1340 pflag->classWichIsNotFound << "<all classes>";
1341 QString name= pflag->name->identifier()->chars();
1342 Trace("- Flag: <all classes>::" + name + " not found!");
1344 iqflags.append(iqflaglist);
1346 missingqflags.append(iqflags);
1348 return missingqflags;
1351 /**************************************
1352 Function that resolves the dependensies
1353 between Q_FLAG, Q_DECLARE_FLAGS
1355 ***************************************/
1356 void ParseManager::assignFlagValues(QFLAGITEM* qflags, const QList<QList<QDECLAREFLAGSITEM*> > &qdeclareflagslookuplist, const QList<QList<ENUMITEM*> > &enumlookuplist)
1360 //try to find if there is a deflare flag macro with the same name as in qflagname
1361 Scope *classMembers = qflags->highestlevelclass->classspec->symbol;
1362 Symbol *s = classMembers->find(qflags->name);
1363 if (s->isTypedef()) {
1364 FullySpecifiedType ty = s->type();
1365 if (Enum *e = ty->asEnumType()) {
1366 enumname = e->name()->identifier()->chars();
1370 //now we have the right enum name now we need to find the enum
1372 foreach(QList<ENUMITEM*> enumitemlist, enumlookuplist){
1373 foreach(ENUMITEM* enumitem, enumitemlist){
1374 EnumSpecifierAST *penumspec = enumitem->ast;
1375 QString enumspecname = enumitem->trlUnit->spell(penumspec->name->firstToken());
1376 if(enumspecname == enumname){
1377 qflags->enumvalues << getEnumValueStringList(enumitem, qflags->name->identifier()->chars());
1386 qflags->foundallenums = false;
1389 /*****************************************
1390 Function that compares if all enums
1391 and flags assigned by using the Q_FLAGS
1392 are complete defined.
1393 *****************************************/
1394 QList<QFLAGITEM*> ParseManager::containsAllFlags(const QList<QFLAGITEM*> &classqflaglist, const QList<QFLAGITEM*> &iclassqflaglist)
1396 QList<QFLAGITEM*> ret;
1397 foreach(QFLAGITEM* iqflags, iclassqflaglist){
1398 if(iqflags->foundallenums){
1400 QStringList missingimplinclasses;
1401 ClassSpecifierAST* clspec = 0;
1402 QString classname = "";
1403 foreach(QFLAGITEM* qflags, classqflaglist){
1404 if(clspec != qflags->highestlevelclass->classspec){
1405 clspec = qflags->highestlevelclass->classspec;
1407 classname += clspec->symbol->name()->identifier()->chars();
1408 if(missingimplinclasses.indexOf(classname) < 0)
1409 missingimplinclasses.push_back(classname);
1411 if(qflags->isEqualTo(iqflags)){
1413 missingimplinclasses.clear();
1414 Trace("- Flag: " + classname + "::" + qflags->name->identifier()->chars() + " found");
1419 iqflags->classWichIsNotFound.append(missingimplinclasses);
1420 ret.push_back(iqflags);
1421 QString classname = iqflags->highestlevelclass->classspec->symbol->name()->identifier()->chars();
1422 Trace("- Flag: " + classname + "::" + iqflags->name->identifier()->chars() + " not found!");
1426 ret.push_back(iqflags);
1431 /************************************
1432 Function that gives back an error
1433 string for a Q_FLAGS mismatch.
1434 ************************************/
1435 QStringList ParseManager::getErrorMessage(QFLAGITEM* pfg)
1440 if(!pfg->foundallenums)
1443 QTextStream out(&tmp);
1445 out << oo(pfg->highestlevelclass->classspec->symbol->name());
1446 out << "::Q_FLAGS "<<pfg->name->identifier()->chars()<< ": enum missing.";
1449 for(int i = 0; i < pfg->classWichIsNotFound.size(); i++){
1451 QTextStream out(&tmp);
1453 out << pfg->classWichIsNotFound[i] << "::Q_FLAGS " << oo(pfg->name);
1459 inline QString ParseManager::getTraceFuntionString(const FUNCTIONITEM *fctitem, const QString& classname)
1463 if(fctitem->function->isPublic())
1465 if(fctitem->function->isProtected())
1467 if(fctitem->function->isPrivate())
1470 if(fctitem->function->isVirtual())
1472 if(fctitem->function->isPureVirtual())
1473 ret += "pure virtual ";
1475 if(fctitem->function->isSignal())
1477 if(fctitem->function->isSlot())
1479 if(fctitem->function->isNormal())
1481 if(fctitem->function->isInvokable())
1482 ret += "Invokable ";
1486 ret += fctitem->trlUnit->spell(fctitem->function->sourceLocation());
1490 void ParseManager::Trace(QString value)
1493 QTextStream out(::m_resultFile);
1497 out << value << endl;
1501 PROPERTYITEM *PROPERTYITEM::create(QtPropertyDeclarationAST *ast, const CLASSLISTITEM *clazz)
1503 PROPERTYITEM *item = new PROPERTYITEM;
1505 item->highestlevelclass = clazz;
1506 item->trlUnit = clazz->trlUnit;
1509 Bind bind(item->trlUnit);
1510 item->type = bind(ast->type_id, clazz->classspec->symbol);
1513 for (QtPropertyDeclarationItemListAST *it = ast->property_declaration_items;
1514 it; it = it->next) {
1515 if (!it->value->item_name_token)
1517 const char *name = item->trlUnit->spell(it->value->item_name_token);
1518 if (!qstrcmp(name, "READ"))
1519 item->readAst = it->value->expression;
1520 else if (!qstrcmp(name, "WRITE"))
1521 item->writeAst = it->value->expression;
1522 else if (!qstrcmp(name, "RESET"))
1523 item->resetAst = it->value->expression;
1524 else if (!qstrcmp(name, "NOTIFY"))
1525 item->notifyAst = it->value->expression;