/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the Qt Mobility Components. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "parsemanager.h" #include "cplusplus/CppDocument.h" #include "./parser/src/shared/cplusplus/CppControl.h" #include "TranslationUnit.h" #include "AST.h" #include "Symbols.h" #include #include "Name.h" #include "cpptools/cppmodelmanager.h" #include using namespace CppTools; using namespace CppTools::Internal; using namespace CPlusPlus; //<------------------------------------------------------- Compare function for the internal structures /********************************** Compares function with function with return type, function name and their arguments and arguments types. **********************************/ bool FUNCTIONITEM::isEqualTo(FUNCTIONITEM *cpfct, bool ignoreName/* = true*/) { if(ignoreName) return function->isEqualTo(cpfct->function, true); return function->isEqualTo(cpfct->function); } /***************************************************************** Compares two property regarding of their function definition, type definition, function arguments and function types. Q_PROPERTY( ConnectionState state READ state NOTIFY stateChanged); ******************************************************************/ bool PROPERTYITEM::isEqualTo(PROPERTYITEM *cpppt) { QString thistype = this->trlUnit->spell(this->ast->type_token); QString cppttype = cpppt->trlUnit->spell(cpppt->ast->type_token); if(thistype != cppttype) return false; QString thistypename = this->trlUnit->spell(this->ast->type_name_token); QString cppttypename = cpppt->trlUnit->spell(cpppt->ast->type_name_token); if(thistypename != cppttypename) return false; if(this->readdefined != cpppt->readdefined) return false; if(this->writedefined != cpppt->writedefined) return false; if(this->resetdefined != cpppt->resetdefined) return false; if(this->notifydefined != cpppt->notifydefined) return false; //check for read function if(this->readdefined){ if(!this->readFct || !cpppt->readFct) return false; if(!this->readFct->isEqualTo(cpppt->readFct)) return false; } //check for write function if(this->writedefined){ if(!this->writeFct || !cpppt->writeFct) return false; if(!this->writeFct->isEqualTo(cpppt->writeFct)) return false; } //check for reset function if(this->resetdefined){ if(!this->resetFct || !cpppt->resetFct) return false; if(!this->resetFct->isEqualTo(cpppt->resetFct)) return false; } //check for notify function if(this->notifydefined){ if(!this->notifyFct || !cpppt->notifyFct) return false; if(!this->notifyFct->isEqualTo(cpppt->notifyFct)) return false; } return true; } /***************************************************************** Compares two enums regarding of their values created by the getEnumValueStringList function. *****************************************************************/ bool QENUMITEM::isEqualTo(QENUMITEM *cpenum) { if(this->values.count() != cpenum->values.count()) return false; foreach(QString str, this->values){ if(!cpenum->values.contains(str)) return false; } return true; } /***************************************************************** Compares two flags regarding of their enum definitions and their values created by the getEnumValueStringList function. *****************************************************************/ bool QFLAGITEM::isEqualTo(QFLAGITEM *cpflag) { if(this->enumvalues.count() != cpflag->enumvalues.count()) return false; foreach(QString str, this->enumvalues){ if(!cpflag->enumvalues.contains(str)) return false; } return true; } ParseManager::ParseManager() : pCppPreprocessor(0) { } ParseManager::~ParseManager() { if(pCppPreprocessor) delete pCppPreprocessor; if(::m_resultFile){ ::m_resultFile->close(); delete ::m_resultFile; ::m_resultFile = 0; } } /************************************** Function for setting the include Paths **************************************/ void ParseManager::setIncludePath(const QStringList &includePath) { m_includePaths = includePath; } /************************************** public Function that starts the parsing all of the files in the sourceFiles string list. **************************************/ void ParseManager::parse(const QStringList &sourceFiles) { m_errormsgs.clear(); if(pCppPreprocessor){ delete pCppPreprocessor; pCppPreprocessor = 0; } if (! sourceFiles.isEmpty()) { m_strHeaderFile = sourceFiles[0]; pCppPreprocessor = new CppTools::Internal::CppPreprocessor(QPointer(this)); pCppPreprocessor->setIncludePaths(m_includePaths); pCppPreprocessor->setFrameworkPaths(m_frameworkPaths); parse(pCppPreprocessor, sourceFiles); } } /********************************************* private function that prepare the filelist to parse and starts the parser. *********************************************/ void ParseManager::parse(CppTools::Internal::CppPreprocessor *preproc, const QStringList &files) { if (files.isEmpty()) return; //check if file is C++ header file QStringList headers; foreach (const QString &file, files) { const QFileInfo fileInfo(file); QString ext = fileInfo.suffix(); if (ext.toLower() == "h") headers.append(file); } foreach (const QString &file, files) { preproc->snapshot.remove(file); } preproc->setTodo(headers); QString conf = QLatin1String(""); preproc->run(conf); for (int i = 0; i < headers.size(); ++i) { QString fileName = headers.at(i); preproc->run(fileName); } } //This function creates a class list for each class and its base classes in //the header file that needs to be checked. //e.g. // Cl1 Cl2 // __|__ __|__ // | | | | // Cl11 Cl12 Cl21 Cl22 // //==> list[0] = {Cl1, Cl11, Cl12} // list[1] = {Cl2, Cl21, Cl22} QList ParseManager::CreateClassLists(bool isInterfaceHeader) { QListret; QList classlist; QList allclasslist; Trace("Following classes scaned for header file: " + m_strHeaderFile); //Iteration over all parsed documents if(getPreProcessor()){ for (Snapshot::const_iterator it = getPreProcessor()->snapshot.begin() ; it != getPreProcessor()->snapshot.end(); ++it) { Document::Ptr doc = (*it); if(doc){ QFileInfo fileinf(doc->fileName()); QFileInfo fileinf1(m_strHeaderFile); //Get the Translated unit Control* ctrl = doc->control(); TranslationUnit* trlUnit = ctrl->translationUnit(); AST* pAst = trlUnit->ast(); TranslationUnitAST *ptrAst = 0; if(pAst && (ptrAst = pAst->asTranslationUnit())){ //iteration over all translated declaration in this document for (DeclarationListAST *pDecllist = ptrAst->declaration_list; pDecllist; pDecllist = pDecllist->next) { if(pDecllist->value){ SimpleDeclarationAST *pSimpleDec = pDecllist->value->asSimpleDeclaration(); if(pSimpleDec){ //Iteration over class specifier for (SpecifierListAST *pSimpleDecDecllist = pSimpleDec->decl_specifier_list; pSimpleDecDecllist; pSimpleDecDecllist = pSimpleDecDecllist->next) { ClassSpecifierAST * pclassspec = pSimpleDecDecllist->value->asClassSpecifier(); if(pclassspec){ CLASSLISTITEM* item = new CLASSLISTITEM(); item->classspec = pclassspec; item->trlUnit = trlUnit; allclasslist.push_back(item); QString classname = item->trlUnit->spell(item->classspec->name->firstToken()); Trace("- " + classname + " class scaned"); //We found a class that is defined in the header file that needs to be checked if(fileinf.fileName().toLower() == fileinf1.fileName().toLower()){ CLASSTREE* cltree = new CLASSTREE(); cltree->highestlevelclass = item; cltree->classlist.push_back(item); ret.push_back(cltree); } } } } } } } } } } //after we search for the classes we need to search for the baseclasses Trace("Following classes found in Header file: " + m_strHeaderFile); foreach(CLASSTREE *cltree, ret){ QString classname = cltree->highestlevelclass->trlUnit->spell(cltree->highestlevelclass->classspec->name->firstToken()); Trace("- " + classname + " class found"); QList baseclasslist; getBaseClasses(cltree->highestlevelclass, baseclasslist, allclasslist, 0, isInterfaceHeader); cltree->classlist.append(baseclasslist); } return ret; } /******************************************** Gets all the baseclass from a class and add those base classes into the baseclasslist ********************************************/ void ParseManager::getBaseClasses(const CLASSLISTITEM* pclass , QList &baseclasslist , const QList &allclasslist , int level , bool isInterfaceHeader) { //iteration over the base_clause_list of the current class QString levelmarker = " "; for(int i = 0; i < level; i++) levelmarker += " "; levelmarker += "|- "; QListchild; for(BaseSpecifierListAST *pBaseSpecList = pclass->classspec->base_clause_list; pBaseSpecList; pBaseSpecList = pBaseSpecList->next) { BaseSpecifierAST *pBaseSpec = pBaseSpecList->value; bool found = false; foreach(CLASSLISTITEM* pclspec, allclasslist) { if(pclspec->classspec->symbol->name() && pBaseSpec->symbol->name() && pclspec->classspec->symbol->name()->isEqualTo(pBaseSpec->symbol->name())) { child.push_back(pclspec); baseclasslist.push_back(pclspec); QString classname = pclspec->trlUnit->spell(pclspec->classspec->name->firstToken()); Trace(levelmarker + classname + " class found"); found = true; break; } } if(!found && pBaseSpec->name){ QString classname = pclass->trlUnit->spell(pBaseSpec->name->firstToken()); if(isInterfaceHeader) Trace(levelmarker + classname + " class not found! Interface classes should not be inherited from Qt Objects!"); else Trace(levelmarker + classname + " class not found!"); } } //call the function recursive because all the basclasses can have other base classes foreach(CLASSLISTITEM* pchclass, child){ getBaseClasses(pchclass, baseclasslist, allclasslist, ++level, isInterfaceHeader); } } /************************************************** This function finds and creates all Elements which are significant for MetaDatas. Those element will be added in the aparameter lists. **************************************************/ void ParseManager::getElements(QList &functionlist , QList &propertylist , QList &qenumlist , QList &enumlist , QList &qflaglist , QList &qdeclareflaglist , const QList classitems , const CLASSLISTITEM* highestlevelclass) { foreach(CLASSLISTITEM* classitem, classitems){ QString classname = ""; if(classitem->classspec->name) classname = classitem->trlUnit->spell(classitem->classspec->name->firstToken()); for (DeclarationListAST *pmemberlist = classitem->classspec->member_specifier_list; pmemberlist; pmemberlist = pmemberlist->next) { /********** Functions **********/ FunctionDefinitionAST *pfctdef = pmemberlist->value->asFunctionDefinition(); if(pfctdef){ FUNCTIONITEM* item = new FUNCTIONITEM(); item->trlUnit = classitem->trlUnit; item->function = pfctdef->symbol; item->classAst = classitem->classspec; item->highestlevelclass = highestlevelclass; functionlist.push_back(item); if(isMetaObjFunction(item)) Trace(" - " + getTraceFuntionString(item, classname) + " found"); } SimpleDeclarationAST *pdecl = pmemberlist->value->asSimpleDeclaration(); if(pdecl){ for(List* decllist = pdecl->symbols; decllist; decllist = decllist->next) { Function* pfct = decllist->value->type()->asFunctionType(); if(pfct){ FUNCTIONITEM* item = new FUNCTIONITEM(); item->trlUnit = classitem->trlUnit; item->function = pfct; item->classAst = classitem->classspec; item->highestlevelclass = highestlevelclass; functionlist.push_back(item); if(isMetaObjFunction(item)) Trace(" - " + getTraceFuntionString(item, classname) + " found"); } } /****** enum ******/ for(List* decllist = pdecl->decl_specifier_list; decllist; decllist = decllist->next) { EnumSpecifierAST * penum = decllist->value->asEnumSpecifier(); if(penum){ ENUMITEM* item = new ENUMITEM(); item->ast = penum; item->highestlevelclass = highestlevelclass; item->trlUnit = classitem->trlUnit; enumlist.push_back(item); } } } else{ /********** Q_PROPERTY **********/ QPropertyDeclarationAST *ppdecl = pmemberlist->value->asQPropertyDeclarationAST(); if(ppdecl){ PROPERTYITEM* item = new PROPERTYITEM(); item->ast = ppdecl; item->highestlevelclass = highestlevelclass; item->trlUnit = classitem->trlUnit; item->readdefined = (ppdecl->read_token > 0); item->writedefined = (ppdecl->write_token > 0); item->resetdefined = (ppdecl->reset_token > 0); item->notifydefined = (ppdecl->notify_token > 0); propertylist.push_back(item); if(item->ast->type_name_token > 0){ QString propertyname = item->trlUnit->spell(item->ast->type_name_token); Trace(" - Q_PROPERTY: " + classname + "::" + propertyname + " found"); } } else{ /********** Q_ENUM **********/ QEnumDeclarationAST *pqenum = pmemberlist->value->asQEnumDeclarationAST(); if(pqenum){ if(pqenum->enumerator_list){ for (EnumeratorListAST *plist = pqenum->enumerator_list; plist; plist = plist->next) { QENUMITEM* item = new QENUMITEM(); item->ast = plist->value; item->highestlevelclass = highestlevelclass; item->trlUnit = classitem->trlUnit; qenumlist.push_back(item); QString enumname = item->trlUnit->spell(item->ast->firstToken()); Trace(" - Q_ENUM: " + classname + "::" + enumname + " found"); } } } else{ /********** Q_FLAGS **********/ QFlagsDeclarationAST *pqflags = pmemberlist->value->asQFlagsDeclarationAST(); if(pqflags){ if(pqflags->enumerator_list){ for (EnumeratorListAST *plist = pqflags->enumerator_list; plist; plist = plist->next) { QFLAGITEM* item = new QFLAGITEM(); item->ast = plist->value; item->highestlevelclass = highestlevelclass; item->trlUnit = classitem->trlUnit; qflaglist.push_back(item); QString enumname = item->trlUnit->spell(plist->firstToken()); Trace(" - Q_FLAGS: " + classname + "::" + enumname + " found"); } } } else { /**************** Q_DECLARE_FLAGS ****************/ QDeclareFlagsDeclarationAST *pqdeclflags = pmemberlist->value->asQDeclareFlagsDeclarationAST(); if(pqdeclflags){ QDECLAREFLAGSITEM* item = new QDECLAREFLAGSITEM(); item->ast = pqdeclflags; item->highestlevelclass = highestlevelclass; item->trlUnit = classitem->trlUnit; qdeclareflaglist.push_back(item); } } } } } } } } /********************************************* Function that starts the comare between the parser result and their metadata content. *********************************************/ bool ParseManager::checkAllMetadatas(ParseManager* pInterfaceParserManager, QString resultfile) { bool ret = true; //Create output file if(!resultfile.isEmpty() && ::m_resultFile == 0){ ::m_resultFile = new QFile(resultfile); if (!::m_resultFile->open(QFile::WriteOnly | QFile::Truncate)) { delete ::m_resultFile; ::m_resultFile = 0; } } /************************************************ Get all elements from the interface header file ************************************************/ Trace("### Get all elements from the interface header file ###"); QList ilookuplist = pInterfaceParserManager->CreateClassLists(true); QList > ifunctionslookuplist; QList > ipropertieslookuplist; QList > iqenumlookuplist; QList > ienumlookuplist; QList > iqflaglookuplist; QList > iqdeclareflaglookuplist; Trace("Following MetaData found:"); foreach(CLASSTREE* iclasstree, ilookuplist){ QListfunctionlist; QListpropertylist; QListqenumlist; QListenumlist; QList qflaglist; QList qdeclareflag; getElements(functionlist , propertylist , qenumlist , enumlist , qflaglist , qdeclareflag , iclasstree->classlist , iclasstree->highestlevelclass); if(functionlist.size() > 0) ifunctionslookuplist.append(functionlist); if(propertylist.size() > 0) ipropertieslookuplist.append(propertylist); if(qenumlist.size() > 0) iqenumlookuplist.append(qenumlist); if(enumlist.size() > 0) ienumlookuplist.append(enumlist); if(qflaglist.size() > 0) iqflaglookuplist.append(qflaglist); if(qdeclareflag.size() > 0) iqdeclareflaglookuplist.append(qdeclareflag); } /************************************************ Get all elements from the compare header file ************************************************/ Trace("\n"); Trace("### Get all elements from the compare header file ###"); QList lookuplist = CreateClassLists(false); QList > functionslookuplist; QList > propertieslookuplist; QList > qenumlookuplist; QList > enumlookuplist; QList > qflaglookuplist; QList > qdeclareflaglookuplist; Trace("Following MetaData found:"); foreach(CLASSTREE* classtree, lookuplist){ QListfunctionlist; QListpropertylist; QListqenumlist; QListenumlist; QList qflaglist; QList qdeclareflag; getElements(functionlist , propertylist , qenumlist , enumlist , qflaglist , qdeclareflag , classtree->classlist , classtree->highestlevelclass); if(functionlist.size() > 0) functionslookuplist.append(functionlist); if(propertylist.size() > 0) propertieslookuplist.append(propertylist); if(qenumlist.size() > 0) qenumlookuplist.append(qenumlist); if(enumlist.size() > 0) enumlookuplist.append(enumlist); if(qflaglist.size() > 0) qflaglookuplist.append(qflaglist); if(qdeclareflag.size() > 0) qdeclareflaglookuplist.append(qdeclareflag); } Trace("\n"); Trace("### Result: ###"); /****************************** Check for function ******************************/ Trace("Compare all interface MetaData functions:"); QList missingifcts = checkMetadataFunctions(functionslookuplist, ifunctionslookuplist); if(missingifcts.size() > 0){ foreach(FUNCTIONITEM* ifct, missingifcts){ m_errormsgs.append(getErrorMessage(ifct)); } ret = false; Trace("- Failed!"); } else{ Trace("- OK"); } /****************************** Check for properties ******************************/ Trace("Compare all interface MetaData properties:"); QList missingippts = checkMetadataProperties(propertieslookuplist, functionslookuplist, ipropertieslookuplist, ifunctionslookuplist); if(missingippts.size() > 0){ foreach(PROPERTYITEM* ippt, missingippts){ m_errormsgs.append(getErrorMessage(ippt)); } ret = false; Trace("- Failed!"); } else{ Trace("- OK"); } /****************************** Check for enums ******************************/ Trace("Compare all interface MetaData enums:"); QList missingiqenums = checkMetadataEnums(qenumlookuplist, enumlookuplist, iqenumlookuplist, ienumlookuplist); if(missingiqenums.size() > 0){ foreach(QENUMITEM* ienum, missingiqenums){ m_errormsgs.append(getErrorMessage(ienum)); } ret = false; Trace("- Failed!"); } else{ Trace("- OK"); } /****************************** Check for flags ******************************/ Trace("Compare all interface MetaData flags:"); QList missingiqflags = checkMetadataFlags(qflaglookuplist, qdeclareflaglookuplist, enumlookuplist , iqflaglookuplist, iqdeclareflaglookuplist, ienumlookuplist); if(missingiqflags.size() > 0){ foreach(QFLAGITEM* iflags, missingiqflags){ m_errormsgs.append(getErrorMessage(iflags)); } ret = false; Trace("- Failed!"); } else{ Trace("- OK"); } /****************************** Add summary ******************************/ Trace("\n"); Trace("### summary ###"); if(m_errormsgs.size() > 0){ Trace("- Following interface items are missing:"); foreach(QString msg, m_errormsgs) Trace(" - " + msg); } else Trace("Interface is full defined."); //now delet all Classitems foreach(CLASSTREE* l, ilookuplist){ l->classlist.clear(); } foreach(CLASSTREE* l, lookuplist){ l->classlist.clear(); } //delete all functionitems foreach(QListl, ifunctionslookuplist){ l.clear(); } foreach(QListl, functionslookuplist){ l.clear(); } //delete all properties foreach(QListl, ipropertieslookuplist){ l.clear(); } foreach(QListl, propertieslookuplist){ l.clear(); } //delete all qenums foreach(QListl, iqenumlookuplist){ l.clear(); } foreach(QListl, iqenumlookuplist){ l.clear(); } //delete all enums foreach(QListl, ienumlookuplist){ l.clear(); } foreach(QListl, enumlookuplist){ l.clear(); } //delete all qflags foreach(QListl, iqflaglookuplist){ l.clear(); } foreach(QListl, qflaglookuplist){ l.clear(); } //delete all qdeclareflags foreach(QListl, iqdeclareflaglookuplist){ l.clear(); } foreach(QListl, qdeclareflaglookuplist){ l.clear(); } return ret; } //<------------------------------------------------------- Start of MetaData functions /*********************************** Function that checks all functions which will occur in the MetaData ***********************************/ QList ParseManager::checkMetadataFunctions(const QList > &classfctlist, const QList > &iclassfctlist) { QList missingifcts; //Compare each function from interface with function from header (incl. baseclass functions) QList ifcts; foreach(QListifunctionlist, iclassfctlist){ ifcts.clear(); //check if one header class contains all function from one interface header class if(classfctlist.count() > 0){ foreach(QListfunctionlist, classfctlist){ QList tmpl = containsAllMetadataFunction(functionlist, ifunctionlist); if(tmpl.size() == 0){ ifcts.clear(); break; } else ifcts.append(tmpl); } } else { foreach(FUNCTIONITEM *pfct, ifunctionlist) pfct->classWichIsNotFound << ""; ifcts.append(ifunctionlist); } missingifcts.append(ifcts); } return missingifcts; } /********************************************* Helper function to check if a function will occur in the MetaData. *********************************************/ bool ParseManager::isMetaObjFunction(FUNCTIONITEM* fct) { if(fct->function->isInvokable() || fct->function->isSignal() || fct->function->isSlot()) return true; return false; } /**************************************************** Check if all function from iclassfctlist are defined in the classfctlist as well. It will return all the function they are missing. ****************************************************/ QList ParseManager::containsAllMetadataFunction(const QList &classfctlist, const QList &iclassfctlist) { QList ret; foreach(FUNCTIONITEM* ifct, iclassfctlist){ if(isMetaObjFunction(ifct)){ bool found = false; QStringList missingimplinclasses; ClassSpecifierAST* clspec = 0; QString classname = ""; foreach(FUNCTIONITEM* fct, classfctlist){ if(clspec != fct->highestlevelclass->classspec){ clspec = fct->highestlevelclass->classspec; //get the classname unsigned int firsttoken = clspec->name->firstToken(); classname += fct->trlUnit->spell(firsttoken); if(missingimplinclasses.indexOf(classname) < 0) missingimplinclasses.push_back(classname); } if(fct->isEqualTo(ifct, false)){ found = true; missingimplinclasses.clear(); Trace("- " + getTraceFuntionString(fct, classname) + " implemented"); break; } } if(!found){ ifct->classWichIsNotFound.append(missingimplinclasses); ret.push_back(ifct); QString classname = ifct->trlUnit->spell(ifct->highestlevelclass->classspec->name->firstToken()); Trace("- " + getTraceFuntionString(ifct, classname) + " not implemented!"); } } } return ret; } /************************************ Function that gives back an error string for a MetaData function mismatch. ************************************/ QStringList ParseManager::getErrorMessage(FUNCTIONITEM* fct) { QStringList ret; QString fctstring = ""; QString fcttype = ""; foreach(QString classname, fct->classWichIsNotFound){ QString tmp; QTextStream out(&tmp); fcttype = ""; fctstring = classname; fctstring += "::"; unsigned int token = fct->function->sourceLocation() - 1; if(token >= 0){ //tok.isNot(T_EOF_SYMBOL) while(fct->trlUnit->tokenAt(token).isNot(T_EOF_SYMBOL)){ fctstring += fct->trlUnit->tokenAt(token).spell(); if(*fct->trlUnit->tokenAt(token).spell() == ')') break; fctstring += " "; token++; } } Function* pfct = fct->function; if(pfct){ fcttype = "type: "; //Check for private, protected and public if(pfct->isPublic()) fcttype = "public "; if(pfct->isProtected()) fcttype = "protected "; if(pfct->isPrivate()) fcttype = "private "; if(pfct->isVirtual()) fcttype += "virtual "; if(pfct->isPureVirtual()) fcttype += "pure virtual "; if(pfct->isSignal()) fcttype += "Signal "; if(pfct->isSlot()) fcttype += "Slot "; if(pfct->isNormal()) fcttype += "Normal "; if(pfct->isInvokable()) fcttype += "Invokable "; } out << fcttype << fctstring; ret << tmp; } return ret; } //---> //<------------------------------------------------------- Start of Q_PROPERTY checks /*********************************** Function that checks all Property which will occur in the MetaData ***********************************/ QList ParseManager::checkMetadataProperties(const QList > &classproplist , const QList > &classfctlist , const QList > &iclassproplist , const QList > &iclassfctlist) { QList missingiprops; //assign the property functions foreach(QListproplist, classproplist){ foreach(PROPERTYITEM* prop, proplist){ assignPropertyFunctions(prop, classfctlist); } } foreach(QListproplist, iclassproplist){ foreach(PROPERTYITEM* prop, proplist){ assignPropertyFunctions(prop, iclassfctlist); } } //Compare each qproperty from interface with qproperty from header (incl. baseclass functions) QList ippts; foreach(QListipropertylist, iclassproplist){ ippts.clear(); //check if one header class contains all function from one interface header class if(classproplist.count() > 0){ foreach(QListpropertylist, classproplist){ QList tmpl = containsAllPropertyFunction(propertylist, ipropertylist); if(tmpl.size() == 0) ippts.clear(); else ippts.append(tmpl); } } else { foreach(PROPERTYITEM *pprop, ipropertylist){ pprop->classWichIsNotFound << ""; QString name = pprop->trlUnit->spell(pprop->ast->type_name_token); Trace("- Property: ::" + name + " not found!"); } ippts.append(ipropertylist); } missingiprops.append(ippts); } return missingiprops; } /************************************** Function that resolves the dependensies between Q_PROPERTY and thier READ, WRITE, NOTIFY and RESET functions. ***************************************/ void ParseManager::assignPropertyFunctions(PROPERTYITEM* prop, const QList > &fctlookuplist) { //get the name of the needed functions QString type; QString readfctname; QString writefctname; QString resetfctname; QString notifyfctname; int needtofind = 0; type = prop->trlUnit->spell(prop->ast->type_token); if(prop->readdefined){ readfctname = prop->trlUnit->spell(prop->ast->read_function_token); needtofind++; } if(prop->writedefined){ writefctname = prop->trlUnit->spell(prop->ast->write_function_token); needtofind++; } if(prop->resetdefined){ resetfctname = prop->trlUnit->spell(prop->ast->reset_function_token); needtofind++; } if(prop->notifydefined){ notifyfctname = prop->trlUnit->spell(prop->ast->notify_function_token); needtofind++; } //Now iterate over all function to find all functions which are defined in the Q_PROPERTY macro if(needtofind > 0){ prop->foundalldefinedfct = false; foreach(QList fctlist, fctlookuplist){ foreach(FUNCTIONITEM* pfct, fctlist){ QString fctname = pfct->trlUnit->spell(pfct->function->sourceLocation()); //check the function type against the property type QString fcttype =pfct->trlUnit->spell(pfct->function->sourceLocation() - 1); if(fctname.length() > 0 && fcttype.length() > 0){ if(prop->readdefined && fctname == readfctname){ if(type != fcttype) continue; prop->readFct = pfct; needtofind--; } if(prop->writedefined && fctname == writefctname){ prop->writeFct = pfct; needtofind--; } if(prop->resetdefined && fctname == resetfctname){ prop->resetFct = pfct; needtofind--; } if(prop->notifydefined && fctname == notifyfctname){ prop->notifyFct = pfct; needtofind--; } if(needtofind <= 0){ //a flag that indicates if a function was missing prop->foundalldefinedfct = true; return; } } } } } } /************************************** Function that checks if all functions dependencies in Q_PROPERTY have the same arguments and retunr value. ***************************************/ QList ParseManager::containsAllPropertyFunction(const QList &classproplist, const QList &iclassproplist) { QList ret; foreach(PROPERTYITEM* ipropt, iclassproplist){ if(ipropt->foundalldefinedfct){ bool found = false; QStringList missingimplinclasses; ClassSpecifierAST* clspec = 0; QString classname = ""; foreach(PROPERTYITEM* propt, classproplist){ if(clspec != propt->highestlevelclass->classspec){ clspec = propt->highestlevelclass->classspec; //get the classname unsigned int firsttoken = clspec->name->firstToken(); classname += propt->trlUnit->spell(firsttoken); if(missingimplinclasses.indexOf(classname) < 0) missingimplinclasses.push_back(classname); } if(propt->isEqualTo(ipropt)){ found = true; missingimplinclasses.clear(); Trace("- Property: " + classname + "::" + propt->trlUnit->spell(propt->ast->type_name_token) + " found"); break; } } if(!found){ ipropt->classWichIsNotFound.append(missingimplinclasses); ret.push_back(ipropt); QString classname = ipropt->trlUnit->spell(ipropt->highestlevelclass->classspec->name->firstToken()); Trace("- Property: " + classname + "::" + ipropt->trlUnit->spell(ipropt->ast->type_name_token) + " not found!"); } } else{ QString classname = ipropt->trlUnit->spell(ipropt->highestlevelclass->classspec->name->firstToken()); QString proptype = ipropt->trlUnit->spell(ipropt->ast->type_name_token); Trace("- Property: " + classname + "::" + proptype + " functions are missing!"); ret.push_back(ipropt); } } return ret; } /************************************ Function that gives back an error string for a Q_PROPERTY mismatch. ************************************/ QStringList ParseManager::getErrorMessage(PROPERTYITEM* ppt) { QStringList ret; QString pptstring = ""; if(!ppt->foundalldefinedfct) { QString tmp; QTextStream out(&tmp); unsigned int firsttoken = ppt->highestlevelclass->classspec->name->firstToken(); unsigned int lasttoken = ppt->highestlevelclass->classspec->name->lastToken(); for(unsigned int i = firsttoken; i < lasttoken; i++){ out << ppt->trlUnit->spell(i); } out << "::"; firsttoken = ppt->ast->firstToken(); lasttoken = ppt->ast->lastToken(); for(unsigned int i = firsttoken; i <= lasttoken; i++){ out << ppt->trlUnit->spell(i) << " "; } out << endl << " -"; if(ppt->readdefined && !ppt->readFct) out << "READ "; if(ppt->writedefined && !ppt->writeFct) out << "WRITE "; if(ppt->resetdefined && !ppt->resetFct) out << "RESET."; if(ppt->notifydefined && !ppt->notifyFct) out << "NOTIFY "; out << "functions missing." << endl; ret << tmp; } for(int i = 0; i < ppt->classWichIsNotFound.size(); i++){ QString tmp; QTextStream out(&tmp); pptstring = ppt->classWichIsNotFound[i]; pptstring += "::"; unsigned int firsttoken = ppt->ast->firstToken(); unsigned int lasttoken = ppt->ast->lastToken(); for(unsigned int i = firsttoken; i <= lasttoken; i++){ pptstring += ppt->trlUnit->spell(i); pptstring += " "; } out << pptstring; ret << tmp; } return ret; } //---> //<------------------------------------------------------- Start of Q_ENUMS checks /*********************************** Function that checks all enums which will occur in the MetaData ***********************************/ QList ParseManager::checkMetadataEnums(const QList > &classqenumlist , const QList > &classenumlist , const QList > &iclassqenumlist , const QList > &iclassenumlist) { QList missingiqenums; //assign the property functions foreach(QListqenumlist, classqenumlist){ foreach(QENUMITEM* qenum, qenumlist){ assignEnumValues(qenum, classenumlist); } } foreach(QListqenumlist, iclassqenumlist){ foreach(QENUMITEM* qenum, qenumlist){ assignEnumValues(qenum, iclassenumlist); } } //Compare each qenum from interface with qenum from header (incl. baseclass functions) QList iqenums; foreach(QListiqenumlist, iclassqenumlist){ iqenums.clear(); //check if one header class contains all function from one interface header class if(classqenumlist.count() > 0){ foreach(QListqenumlist, classqenumlist){ QList tmpl = containsAllEnums(qenumlist, iqenumlist); if(tmpl.size() == 0) iqenums.clear(); else iqenums.append(tmpl); } } else { foreach(QENUMITEM *qenum, iqenumlist){ qenum->classWichIsNotFound << ""; QString name= qenum->trlUnit->spell(qenum->ast->firstToken()); Trace("- Enum: ::" + name + " not found!"); } iqenums.append(iqenumlist); } missingiqenums.append(iqenums); } return missingiqenums; } /********************************************* Helper function which creates a string out of an enumerator including its values. *********************************************/ QStringList ParseManager::getEnumValueStringList(ENUMITEM *penum, QString mappedenumname/* = ""*/) { QStringList ret; EnumSpecifierAST *penumsec = penum->ast; QString enumname = penum->trlUnit->spell(penumsec->name->firstToken()); int enumvalue = 0; //now iterrate over all enumitems and create a string like following: //EnumName.EnumItemName.Value //ConnectionState.disconnected.0 for (EnumeratorListAST *plist = penum->ast->enumerator_list; plist; plist = plist->next) { QString value = enumname; if(mappedenumname.size() > 0) value = mappedenumname; value += "."; value += penum->trlUnit->spell(plist->value->identifier_token); value += "."; if(plist->value->equal_token > 0 && plist->value->expression){ QString v = penum->trlUnit->spell(plist->value->expression->firstToken()); bool ch; int newval = enumvalue; if(v.indexOf("0x") >= 0) newval = v.toInt(&ch, 16); else newval = v.toInt(&ch, 10); if(ch) enumvalue = newval; } value += QString::number(enumvalue); enumvalue++; // now add this enumitem string in the VALUE list ret << value; } return ret; } /************************************** Function that resolves the dependensies between Q_ENUMS and enums. ***************************************/ void ParseManager::assignEnumValues(QENUMITEM* qenum, const QList > &enumlookuplist) { QString enumname; EnumeratorAST *penum = qenum->ast->asEnumerator(); if(penum){ //get the name of the enum definition enumname = qenum->trlUnit->spell(penum->firstToken()); //iterate over all enums and find the one with the same name like enumname bool found = false; foreach (QList penumlist, enumlookuplist) { foreach(ENUMITEM *penum, penumlist){ EnumSpecifierAST *penumsec = penum->ast; QString enumname1 = penum->trlUnit->spell(penumsec->name->firstToken()); if(enumname == enumname1){ qenum->values << getEnumValueStringList(penum); found = true; break; } } if(!found) qenum->foundallenums = false; } } } /*********************************** Function that checkt if the Q_ENUMS are completed defined and if the Enum values are the same. ***********************************/ QList ParseManager::containsAllEnums(const QList &classqenumlist, const QList &iclassqenumlist) { QList ret; foreach(QENUMITEM* iqenum, iclassqenumlist){ bool found = false; QStringList missingimplinclasses; ClassSpecifierAST* clspec = 0; QString classname = ""; foreach(QENUMITEM* qenum, classqenumlist){ if(clspec != qenum->highestlevelclass->classspec){ clspec = qenum->highestlevelclass->classspec; //get the classname unsigned int firsttoken = clspec->name->firstToken(); classname += qenum->trlUnit->spell(firsttoken); if(missingimplinclasses.indexOf(classname) < 0) missingimplinclasses.push_back(classname); } if(qenum->isEqualTo(iqenum)){ found = true; missingimplinclasses.clear(); Trace("- Enum: " + classname + "::" + qenum->trlUnit->spell(qenum->ast->firstToken()) + " found"); break; } } if(!found){ iqenum->classWichIsNotFound.append(missingimplinclasses); ret.push_back(iqenum); QString classname = iqenum->trlUnit->spell(iqenum->highestlevelclass->classspec->name->firstToken()); Trace("- Enum: " + classname + "::" + iqenum->trlUnit->spell(iqenum->ast->firstToken()) + " not found!"); } } return ret; } /************************************ Function that gives back an error string for a Q_ENUMS mismatch. ************************************/ QStringList ParseManager::getErrorMessage(QENUMITEM* qenum) { QStringList ret; if(!qenum->foundallenums) { QString tmp; QTextStream out(&tmp); unsigned int firsttoken = qenum->highestlevelclass->classspec->name->firstToken(); unsigned int lasttoken = qenum->highestlevelclass->classspec->name->lastToken(); for(unsigned int i = firsttoken; i < lasttoken; i++){ out << qenum->trlUnit->spell(i); } out << "::Q_ENUMS ( "; firsttoken = qenum->ast->firstToken(); lasttoken = qenum->ast->lastToken(); for(unsigned int i = firsttoken; i < lasttoken; i++) out << qenum->trlUnit->spell(i) << " "; out << ")"; out << endl << " - one or more Enums missing." << endl; ret << tmp; } for(int i = 0; i < qenum->classWichIsNotFound.size(); i++){ QString tmp; QTextStream out(&tmp); out << qenum->classWichIsNotFound[i] << "::Q_ENUMS ( "; unsigned int firsttoken = qenum->ast->firstToken(); unsigned int lasttoken = qenum->ast->lastToken(); for(unsigned int i = firsttoken; i < lasttoken; i++) out << qenum->trlUnit->spell(i) << " "; out << ")"; ret << tmp; } return ret; } //---> //<------------------------------------------------------- Start of Q_FLAGS checks /*********************************** Function that checks all flags which will occur in the MetaData ***********************************/ QList ParseManager::checkMetadataFlags(const QList > &classqflaglist , const QList > &classqdeclareflaglist , const QList > &classenumlist , const QList > &iclassqflaglist , const QList > &iclassqdeclareflaglist , const QList > &iclassenumlist) { QList missingqflags; //assign the enums to the flags foreach(QListqflaglist, classqflaglist){ foreach(QFLAGITEM* qflag, qflaglist){ assignFlagValues(qflag, classqdeclareflaglist, classenumlist); } } foreach(QListqflaglist, iclassqflaglist){ foreach(QFLAGITEM* qflag, qflaglist){ assignFlagValues(qflag, iclassqdeclareflaglist, iclassenumlist); } } //Compare each qenum from interface with qenum from header (incl. baseclass functions) QList iqflags; foreach(QListiqflaglist, iclassqflaglist){ iqflags.clear(); //check if one header class contains all function from one interface header class if(classqflaglist.count() >0){ foreach(QListqflaglist, classqflaglist){ QList tmpl = containsAllFlags(qflaglist, iqflaglist); if(tmpl.size() == 0) iqflags.clear(); else iqflags.append(tmpl); } } else { foreach(QFLAGITEM *pflag, iqflaglist){ pflag->classWichIsNotFound << ""; QString name= pflag->trlUnit->spell(pflag->ast->firstToken()); Trace("- Flag: ::" + name + " not found!"); } iqflags.append(iqflaglist); } missingqflags.append(iqflags); } return missingqflags; } /************************************** Function that resolves the dependensies between Q_FLAG, Q_DECLARE_FLAGS and enums. ***************************************/ void ParseManager::assignFlagValues(QFLAGITEM* qflags, const QList > &qdeclareflagslookuplist, const QList > &enumlookuplist) { QString qflagname; QString enumname; //read the flag names EnumeratorAST *pflags = qflags->ast->asEnumerator(); if(pflags){ qflagname = qflags->trlUnit->spell(pflags->firstToken()); enumname = qflagname; //try to find if there is a deflare flag macro with the same name as in qflagname bool found = false; foreach(QList qdeclarelist, qdeclareflagslookuplist){ foreach(QDECLAREFLAGSITEM* qdeclare, qdeclarelist){ QString declarename = qdeclare->trlUnit->spell(qdeclare->ast->flag_token); if(declarename == qflagname){ //now map the right enum name to the flag enumname = qdeclare->trlUnit->spell(qdeclare->ast->enum_token); found = true; break; } } if(found) break; } //now we have the right enum name now we need to find the enum found = false; foreach(QList enumitemlist, enumlookuplist){ foreach(ENUMITEM* enumitem, enumitemlist){ EnumSpecifierAST *penumspec = enumitem->ast; QString enumspecname = enumitem->trlUnit->spell(penumspec->name->firstToken()); if(enumspecname == enumname){ qflags->enumvalues << getEnumValueStringList(enumitem, qflagname); found = true; break; } } if(found) break; } if(!found) qflags->foundallenums = false; } } /***************************************** Function that compares if all enums and flags assigned by using the Q_FLAGS are complete defined. *****************************************/ QList ParseManager::containsAllFlags(const QList &classqflaglist, const QList &iclassqflaglist) { QList ret; foreach(QFLAGITEM* iqflags, iclassqflaglist){ if(iqflags->foundallenums){ bool found = false; QStringList missingimplinclasses; ClassSpecifierAST* clspec = 0; QString classname = ""; foreach(QFLAGITEM* qflags, classqflaglist){ if(clspec != qflags->highestlevelclass->classspec){ clspec = qflags->highestlevelclass->classspec; //get the classname unsigned int firsttoken = clspec->name->firstToken(); classname += qflags->trlUnit->spell(firsttoken); if(missingimplinclasses.indexOf(classname) < 0) missingimplinclasses.push_back(classname); } if(qflags->isEqualTo(iqflags)){ found = true; missingimplinclasses.clear(); Trace("- Flag: " + classname + "::" + qflags->trlUnit->spell(qflags->ast->firstToken()) + " found"); break; } } if(!found){ iqflags->classWichIsNotFound.append(missingimplinclasses); ret.push_back(iqflags); QString classname = iqflags->trlUnit->spell(iqflags->highestlevelclass->classspec->name->firstToken()); Trace("- Flag: " + classname + "::" + iqflags->trlUnit->spell(iqflags->ast->firstToken()) + " not found!"); } } else ret.push_back(iqflags); } return ret; } /************************************ Function that gives back an error string for a Q_FLAGS mismatch. ************************************/ QStringList ParseManager::getErrorMessage(QFLAGITEM* pfg) { QStringList ret; if(!pfg->foundallenums) { QString tmp; QTextStream out(&tmp); unsigned int firsttoken = pfg->highestlevelclass->classspec->name->firstToken(); unsigned int lasttoken = pfg->highestlevelclass->classspec->name->lastToken(); for(unsigned int i = firsttoken; i < lasttoken; i++){ out << pfg->trlUnit->spell(i); } out << "::Q_FLAGS ( "; firsttoken = pfg->ast->firstToken(); lasttoken = pfg->ast->lastToken(); for(unsigned int i = firsttoken; i < lasttoken; i++) out << pfg->trlUnit->spell(i) << " "; out << ")"; out << endl << " - one or more Enums missing." << endl; ret << tmp; } for(int i = 0; i < pfg->classWichIsNotFound.size(); i++){ QString tmp; QTextStream out(&tmp); out << pfg->classWichIsNotFound[i] << "::Q_FLAGS ( "; unsigned int firsttoken = pfg->ast->firstToken(); unsigned int lasttoken = pfg->ast->lastToken(); for(unsigned int i = firsttoken; i < lasttoken; i++) out << pfg->trlUnit->spell(i) << " "; out << ")"; ret << tmp; } return ret; } inline QString ParseManager::getTraceFuntionString(const FUNCTIONITEM *fctitem, const QString& classname) { QString ret; if(fctitem->function->isPublic()) ret = "public "; if(fctitem->function->isProtected()) ret = "protected "; if(fctitem->function->isPrivate()) ret = "private "; if(fctitem->function->isVirtual()) ret += "virtual "; if(fctitem->function->isPureVirtual()) ret += "pure virtual "; if(fctitem->function->isSignal()) ret += "Signal "; if(fctitem->function->isSlot()) ret += "Slot "; if(fctitem->function->isNormal()) ret += "Normal "; if(fctitem->function->isInvokable()) ret += "Invokable "; ret += classname; ret += "::"; ret += fctitem->trlUnit->spell(fctitem->function->sourceLocation()); return ret; } void ParseManager::Trace(QString value) { if(::m_resultFile){ QTextStream out(::m_resultFile); if(value == "\n") out << endl; else out << value << endl; } } //--->