/************************************************************************** ** ** This file is part of Qt Creator ** ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). ** ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** No Commercial Usage ** ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** 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, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** **************************************************************************/ #include "parsemanager.h" #include "cplusplus/CppDocument.h" #include "Control.h" #include "Literals.h" #include "Overview.h" #include "Scope.h" #include "TranslationUnit.h" #include "AST.h" #include "Symbols.h" #include "Bind.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) { if (!ast->type_id || !cpppt->ast->type_id) return false; if (type != cpppt->type) return false; if (!ast->property_name || !ast->property_name->name || !ast->property_name->name->identifier()) return false; QString thistypename = ast->property_name->name->identifier()->chars(); if (!cpppt->ast->property_name || !cpppt->ast->property_name->name || !cpppt->ast->property_name->name->identifier()) return false; QString cppttypename = cpppt->ast->property_name->name->identifier()->chars(); if(thistypename != cppttypename) return false; if ((this->readAst == 0) != (cpppt->readAst == 0)) return false; if((this->writeAst == 0) != (cpppt->writeAst == 0)) return false; if((this->resetAst == 0) != (cpppt->resetAst == 0)) return false; if((this->notifyAst == 0) != (cpppt->notifyAst == 0)) return false; //check for read function if(this->readAst){ if(!this->readFct || !cpppt->readFct) return false; if(!this->readFct->isEqualTo(cpppt->readFct)) return false; } //check for write function if(this->writeAst){ if(!this->writeFct || !cpppt->writeFct) return false; if(!this->writeFct->isEqualTo(cpppt->writeFct)) return false; } //check for reset function if(this->resetAst){ if(!this->resetFct || !cpppt->resetFct) return false; if(!this->resetFct->isEqualTo(cpppt->resetFct)) return false; } //check for notify function if(this->notifyAst){ 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 wich 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 **********/ if (FunctionDefinitionAST *pfctdef = pmemberlist->value->asFunctionDefinition()){ 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 **********/ if(QtPropertyDeclarationAST *ppdecl = pmemberlist->value->asQtPropertyDeclaration()) { propertylist.push_back(PROPERTYITEM::create(ppdecl, highestlevelclass)); if (ppdecl->property_name && ppdecl->property_name->name && ppdecl->property_name->name->identifier()) { Trace(" - Q_PROPERTY: " + QLatin1String(ppdecl->property_name->name->identifier()->chars()) + " found"); } } else{ /********** Q_ENUM **********/ if (QtEnumDeclarationAST *pqenum = pmemberlist->value->asQtEnumDeclaration()) { for (NameListAST *plist = pqenum->enumerator_list; plist; plist = plist->next) { QENUMITEM* item = new QENUMITEM; item->name = plist->value->name->identifier()->chars(); item->highestlevelclass = highestlevelclass; qenumlist.push_back(item); Trace(" - Q_ENUM: " + classname + "::" + item->name + " found"); } } else{ /********** Q_FLAGS **********/ if (QtFlagsDeclarationAST *pqflags = pmemberlist->value->asQtFlagsDeclaration()){ for (NameListAST *plist = pqflags->flag_enums_list; plist; plist = plist->next) { QFLAGITEM* item = new QFLAGITEM; item->name = plist->value->name; item->highestlevelclass = highestlevelclass; qflaglist.push_back(item); Trace(" - Q_FLAGS: " + classname + "::" + item->name->identifier()->chars() + " found"); } } #if 0 /*The code for Q_DECLARE_FLAGS was wrong. It's optional, and only does a typedef. That means, if you do the typedef yourself and not use Q_DECLARE_FLAGS, that *is* valid. 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.*/ else { /**************** Q_DECLARE_FLAGS ****************/ QtDeclareFlagsDeclarationAST *pqdeclflags = pmemberlist->value->asQDeclareFlagsDeclarationAST(); if(pqdeclflags){ QDECLAREFLAGSITEM* item = new QDECLAREFLAGSITEM(); item->ast = pqdeclflags; item->highestlevelclass = highestlevelclass; item->trlUnit = classitem->trlUnit; qdeclareflaglist.push_back(item); } } #endif } } } } } } /********************************************* 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 != "" && ::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 properies ******************************/ 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("- Folowing 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 occure 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; 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->ast->property_name->name->identifier()->chars(); Trace("- Property: ::" + name + " not found!"); } ippts.append(ipropertylist); } missingiprops.append(ippts); } return missingiprops; } static QString findName(ExpressionAST *ast) { // The "old" icheck code assumed that functions were only a single identifier, so I'll assume the same: if (NameAST *nameAST = ast->asName()) return nameAST->name->identifier()->chars(); else return QString(); } /************************************** 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 readfctname; QString writefctname; QString resetfctname; QString notifyfctname; int needtofind = 0; if(prop->readAst){ readfctname = findName(prop->readAst); needtofind++; } if(prop->writeAst){ writefctname = findName(prop->writeAst); needtofind++; } if(prop->resetAst){ resetfctname = findName(prop->resetAst); needtofind++; } if(prop->notifyAst){ notifyfctname = findName(prop->notifyAst); needtofind++; } //Now iterate over all function to find all functions wich 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 FullySpecifiedType retTy = pfct->function->returnType(); if (!fctname.isEmpty() && retTy.isValid()) { if(prop->readAst && fctname == readfctname){ if (prop->type != retTy) continue; prop->readFct = pfct; needtofind--; } if(prop->writeAst && fctname == writefctname){ prop->writeFct = pfct; needtofind--; } if(prop->resetAst && fctname == resetfctname){ prop->resetFct = pfct; needtofind--; } if(prop->notifyAst && 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->ast->property_name->name->identifier()->chars() + " 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->ast->property_name->name->identifier()->chars() + " not found!"); } } else{ QString classname = ipropt->trlUnit->spell(ipropt->highestlevelclass->classspec->name->firstToken()); Overview oo; QString proptype = oo(ipropt->type); 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->readAst && !ppt->readFct) out << "READ "; if(ppt->writeAst && !ppt->writeFct) out << "WRITE "; if(ppt->resetAst && !ppt->resetFct) out << "RESET."; if(ppt->notifyAst && !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 << ""; Trace("- Enum: ::" + qenum->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) { //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(qenum->name == 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) { Overview oo; 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 classname += oo(clspec->symbol); if(missingimplinclasses.indexOf(classname) < 0) missingimplinclasses.push_back(classname); } if(qenum->isEqualTo(iqenum)){ found = true; missingimplinclasses.clear(); Trace("- Enum: " + classname + "::" + qenum->name + " found"); break; } } if(!found){ iqenum->classWichIsNotFound.append(missingimplinclasses); ret.push_back(iqenum); QString classname = oo(iqenum->highestlevelclass->classspec->symbol); Trace("- Enum: " + classname + "::" + iqenum->name + " not found!"); } } return ret; } /************************************ Function that gives back an error string for a Q_ENUMS mismatch. ************************************/ QStringList ParseManager::getErrorMessage(QENUMITEM* qenum) { Overview oo; QStringList ret; if(!qenum->foundallenums) { QString tmp; QTextStream out(&tmp); out << oo(qenum->highestlevelclass->classspec->symbol); out << "::Q_ENUMS " << qenum->name << " enum missing."; ret << tmp; } for (int i = 0; i < qenum->classWichIsNotFound.size(); i++){ QString tmp; QTextStream out(&tmp); out << qenum->classWichIsNotFound[i] << "::Q_ENUMS " << qenum->name; 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->name->identifier()->chars(); 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 enumname; //try to find if there is a deflare flag macro with the same name as in qflagname Scope *classMembers = qflags->highestlevelclass->classspec->symbol; Symbol *s = classMembers->find(qflags->name); if (s->isTypedef()) { FullySpecifiedType ty = s->type(); if (Enum *e = ty->asEnumType()) { enumname = e->name()->identifier()->chars(); } } //now we have the right enum name now we need to find the enum bool 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, qflags->name->identifier()->chars()); 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 classname += clspec->symbol->name()->identifier()->chars(); if(missingimplinclasses.indexOf(classname) < 0) missingimplinclasses.push_back(classname); } if(qflags->isEqualTo(iqflags)){ found = true; missingimplinclasses.clear(); Trace("- Flag: " + classname + "::" + qflags->name->identifier()->chars() + " found"); break; } } if(!found){ iqflags->classWichIsNotFound.append(missingimplinclasses); ret.push_back(iqflags); QString classname = iqflags->highestlevelclass->classspec->symbol->name()->identifier()->chars(); Trace("- Flag: " + classname + "::" + iqflags->name->identifier()->chars() + " 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) { Overview oo; QStringList ret; if(!pfg->foundallenums) { QString tmp; QTextStream out(&tmp); out << oo(pfg->highestlevelclass->classspec->symbol->name()); out << "::Q_FLAGS "<name->identifier()->chars()<< ": enum missing."; ret << tmp; } for(int i = 0; i < pfg->classWichIsNotFound.size(); i++){ QString tmp; QTextStream out(&tmp); out << pfg->classWichIsNotFound[i] << "::Q_FLAGS " << oo(pfg->name); 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; } } PROPERTYITEM *PROPERTYITEM::create(QtPropertyDeclarationAST *ast, const CLASSLISTITEM *clazz) { PROPERTYITEM *item = new PROPERTYITEM; item->ast = ast; item->highestlevelclass = clazz; item->trlUnit = clazz->trlUnit; if (ast->type_id) { Bind bind(item->trlUnit); item->type = bind(ast->type_id, clazz->classspec->symbol); } for (QtPropertyDeclarationItemListAST *it = ast->property_declaration_items; it; it = it->next) { if (!it->value->item_name_token) continue; const char *name = item->trlUnit->spell(it->value->item_name_token); if (!qstrcmp(name, "READ")) item->readAst = it->value->expression; else if (!qstrcmp(name, "WRITE")) item->writeAst = it->value->expression; else if (!qstrcmp(name, "RESET")) item->resetAst = it->value->expression; else if (!qstrcmp(name, "NOTIFY")) item->notifyAst = it->value->expression; } return item; } //--->