void CppTree2Uml::parseFunctionDeclaration(GroupAST* funSpec, GroupAST* storageSpec, TypeSpecifierAST * typeSpec, InitDeclaratorAST * decl) { bool isFriend = false; //:unused: bool isVirtual = false; bool isStatic = false; //:unused: bool isInline = false; bool isPure = decl->initializer() != 0; bool isConstructor = false; if (funSpec){ //:unused: QList<AST*> l = funSpec->nodeList(); //:unused: for (int i = 0; i < l.size(); ++i) { //:unused: QString text = l.at(i)->text(); //:unused: if (text == QLatin1String("virtual")) isVirtual = true; //:unused: else if (text == QLatin1String("inline")) isInline = true; //:unused: } } if (storageSpec){ QList<AST*> l = storageSpec->nodeList(); for (int i = 0; i < l.size(); ++i) { QString text = l.at(i)->text(); if (text == QLatin1String("friend")) isFriend = true; else if (text == QLatin1String("static")) isStatic = true; } } DeclaratorAST* d = decl->declarator(); QString id = d->declaratorId()->unqualifiedName()->text(); UMLClassifier *c = m_currentClass[m_clsCnt]; if (c == NULL) { uDebug() << id << ": need a surrounding class."; return; } QString returnType = typeOfDeclaration(typeSpec, d); UMLOperation *m = Import_Utils::makeOperation(c, id); // if a class has no return type, it could de a constructor or // a destructor if (d && returnType.isEmpty() && id.indexOf(QLatin1Char('~')) == -1) isConstructor = true; parseFunctionArguments(d, m); Import_Utils::insertMethod(c, m, m_currentAccess, returnType, isStatic, isPure, isFriend, isConstructor, m_comment); m_comment = QString(); }
void scopeOfNode( AST* ast, QStringList& scope ) { if( !ast ) return; if( ast->parent() ) scopeOfNode( ast->parent(), scope ); QString s; switch( ast->nodeType() ) { case NodeType_ClassSpecifier: if( ((ClassSpecifierAST*)ast)->name() ){ s = ((ClassSpecifierAST*)ast)->name()->text(); s = s.isEmpty() ? QString::fromLatin1("<unnamed>") : s; scope.push_back( s ); } break; case NodeType_Namespace: { AST* namespaceName = ((NamespaceAST*)ast)->namespaceName(); s = namespaceName ? namespaceName->text() : QString::fromLatin1("<unnamed>"); scope.push_back( s ); } break; case NodeType_FunctionDefinition: { FunctionDefinitionAST* funDef = static_cast<FunctionDefinitionAST*>( ast ); DeclaratorAST* d = funDef->initDeclarator()->declarator(); // hotfix for bug #68726 if ( !d->declaratorId() ) break; QList<ClassOrNamespaceNameAST*> l = d->declaratorId()->classOrNamespaceNameList(); for( int i = 0; i < l.size(); ++i ) { AST* name = l.at(i)->name(); scope.push_back( name->text() ); } } break; default: break; } }
void CppTree2Uml::parseTemplateDeclaration(TemplateDeclarationAST* ast) { TemplateParameterListAST* parmListAST = ast->templateParameterList(); if (parmListAST == NULL) return; QList<TemplateParameterAST*> parmList = parmListAST->templateParameterList(); for (int i = 0; i < parmList.size(); ++i) { // The template is either a typeParameter or a typeValueParameter. TemplateParameterAST* tmplParmNode = parmList.at(i); TypeParameterAST* typeParmNode = tmplParmNode->typeParameter(); if (typeParmNode) { NameAST* nameNode = typeParmNode->name(); if (nameNode) { QString typeName = nameNode->unqualifiedName()->text(); Model_Utils::NameAndType nt(typeName, NULL); m_templateParams.append(nt); } else { uError() << "nameNode is NULL"; } } ParameterDeclarationAST* valueNode = tmplParmNode->typeValueParameter(); if (valueNode) { TypeSpecifierAST* typeSpec = valueNode->typeSpec(); if (typeSpec == NULL) { uError() << "typeSpec is NULL"; continue; } QString typeName = typeSpec->name()->text(); UMLObject *t = Import_Utils::createUMLObject(UMLObject::ot_UMLObject, typeName, m_currentNamespace[m_nsCnt]); DeclaratorAST* declNode = valueNode->declarator(); NameAST* nameNode = declNode->declaratorId(); if (nameNode == NULL) { uError() << "CppTree2Uml::parseTemplateDeclaration(value):" << " nameNode is NULL"; continue; } QString paramName = nameNode->unqualifiedName()->text(); Model_Utils::NameAndType nt(paramName, t); m_templateParams.append(nt); } } if (ast->declaration()) TreeParser::parseDeclaration(ast->declaration()); }
void CppTree2Uml::parseDeclaration2(GroupAST* funSpec, GroupAST* storageSpec, TypeSpecifierAST* typeSpec, InitDeclaratorAST* decl) { if (m_inStorageSpec) return; DeclaratorAST* d = decl->declarator(); if (!d) return; if (!d->subDeclarator() && d->parameterDeclarationClause()) return parseFunctionDeclaration(funSpec, storageSpec, typeSpec, decl); DeclaratorAST* t = d; while (t && t->subDeclarator()) t = t->subDeclarator(); QString id; if (t && t->declaratorId() && t->declaratorId()->unqualifiedName()) id = t->declaratorId()->unqualifiedName()->text(); if (!scopeOfDeclarator(d, QStringList()).isEmpty()){ uDebug() << id << ": skipping."; return; } UMLClassifier *c = m_currentClass[m_clsCnt]; if (c == NULL) { uDebug() << id << ": need a surrounding class."; return; } QString typeName = typeOfDeclaration(typeSpec, d); //:unused: bool isFriend = false; bool isStatic = false; //:unused: bool isInitialized = decl->initializer() != 0; if (storageSpec){ QList<AST*> l = storageSpec->nodeList(); for (int i = 0; i < l.size(); ++i) { QString text = l.at(i)->text(); if (text == QLatin1String("static")) isStatic = true; //:unused: else if (text == QLatin1String("friend")) isFriend = true; } } Import_Utils::insertAttribute(c, m_currentAccess, id, typeName, m_comment, isStatic); m_comment = QString(); }
/*! Handle declaration in foreach statement */ bool PointerDeclarationFormatter::visit(ForeachStatementAST *ast) { CHECK_RV(ast, "Invalid AST", true); printCandidate(ast); DeclaratorAST *declarator = ast->declarator; CHECK_RV(declarator, "No declarator", true); CHECK_RV(declarator->ptr_operator_list, "No Pointer or references", true); CHECK_RV(ast->type_specifier_list, "No type specifier", true); SpecifierAST *firstSpecifier = ast->type_specifier_list->value; CHECK_RV(firstSpecifier, "No first type specifier", true); CHECK_RV(ast->symbol, "No symbol", true); Symbol *symbol = ast->symbol->memberAt(0); // Specify activation range const int lastActivationToken = declarator->equal_token ? declarator->equal_token - 1 : declarator->lastToken() - 1; TokenRange range(firstSpecifier->firstToken(), lastActivationToken); checkAndRewrite(declarator, symbol, range); return true; }
/*! Handle (1) Simple declarations like in "char *s, *t, *int foo();" (2) Return types of function declarations. */ bool PointerDeclarationFormatter::visit(SimpleDeclarationAST *ast) { CHECK_RV(ast, "Invalid AST", true); printCandidate(ast); const unsigned tokenKind = tokenAt(ast->firstToken()).kind(); const bool astIsOk = tokenKind != T_CLASS && tokenKind != T_STRUCT && tokenKind != T_ENUM; CHECK_RV(astIsOk, "Nothing to do for class/struct/enum", true); DeclaratorListAST *declaratorList = ast->declarator_list; CHECK_RV(declaratorList, "No declarator list", true); DeclaratorAST *firstDeclarator = declaratorList->value; CHECK_RV(firstDeclarator, "No declarator", true); CHECK_RV(ast->symbols, "No Symbols", true); CHECK_RV(ast->symbols->value, "No Symbol", true); List<Symbol *> *sit = ast->symbols; DeclaratorListAST *dit = declaratorList; for (; sit && dit; sit = sit->next, dit = dit->next) { DeclaratorAST *declarator = dit->value; Symbol *symbol = sit->value; const bool isFirstDeclarator = declarator == firstDeclarator; // If were not handling the first declarator, we need to remove // characters from the beginning since our rewritten declaration // will contain all type specifiers. int charactersToRemove = 0; if (!isFirstDeclarator) { const int startAST = m_cppRefactoringFile->startOf(ast); const int startFirstDeclarator = m_cppRefactoringFile->startOf(firstDeclarator); CHECK_RV(startAST < startFirstDeclarator, "No specifier", true); charactersToRemove = startFirstDeclarator - startAST; } // Specify activation range int lastActivationToken = 0; TokenRange range; // (2) Handle function declaration's return type if (symbol->type()->asFunctionType()) { PostfixDeclaratorListAST *pfDeclaratorList = declarator->postfix_declarator_list; CHECK_RV(pfDeclaratorList, "No postfix declarator list", true); PostfixDeclaratorAST *pfDeclarator = pfDeclaratorList->value; CHECK_RV(pfDeclarator, "No postfix declarator", true); FunctionDeclaratorAST *functionDeclarator = pfDeclarator->asFunctionDeclarator(); CHECK_RV(functionDeclarator, "No function declarator", true); // End the activation range before the '(' token. lastActivationToken = functionDeclarator->lparen_token - 1; SpecifierListAST *specifierList = isFirstDeclarator ? ast->decl_specifier_list : declarator->attribute_list; unsigned firstActivationToken = 0; bool foundBegin = false; firstActivationToken = firstTypeSpecifierWithoutFollowingAttribute( specifierList, m_cppRefactoringFile->cppDocument()->translationUnit(), lastActivationToken, &foundBegin); if (!foundBegin) { CHECK_RV(!isFirstDeclarator, "Declaration without attributes not supported", true); firstActivationToken = declarator->firstToken(); } range.start = firstActivationToken; // (1) Handle 'normal' declarations. } else { if (isFirstDeclarator) { bool foundBegin = false; unsigned firstActivationToken = firstTypeSpecifierWithoutFollowingAttribute( ast->decl_specifier_list, m_cppRefactoringFile->cppDocument()->translationUnit(), declarator->firstToken(), &foundBegin); CHECK_RV(foundBegin, "Declaration without attributes not supported", true); range.start = firstActivationToken; } else { range.start = declarator->firstToken(); } lastActivationToken = declarator->equal_token ? declarator->equal_token - 1 : declarator->lastToken() - 1; } range.end = lastActivationToken; checkAndRewrite(declarator, symbol, range, charactersToRemove); } return true; }
void CppTree2Uml::parseFunctionDefinition(FunctionDefinitionAST* ast) { TypeSpecifierAST* typeSpec = ast->typeSpec(); GroupAST* funSpec = ast->functionSpecifier(); GroupAST* storageSpec = ast->storageSpecifier(); if (!ast->initDeclarator()) return; DeclaratorAST* d = ast->initDeclarator()->declarator(); if (!d->declaratorId()) return; bool isFriend = false; //:unused: bool isVirtual = false; bool isStatic = false; //:unused: bool isInline = false; bool isConstructor = false; if (funSpec){ //:unused: QList<AST*> l = funSpec->nodeList(); //:unused: for (int i = 0; i < l.size(); ++i) { //:unused: QString text = l.at(i)->text(); //:unused: if (text == "virtual") isVirtual = true; //:unused: else if (text == "inline") isInline = true; //:unused: } } if (storageSpec){ QList<AST*> l = storageSpec->nodeList(); for (int i = 0; i < l.size(); ++i) { QString text = l.at(i)->text(); if (text == QLatin1String("friend")) isFriend = true; else if (text == QLatin1String("static")) isStatic = true; } } QString id = d->declaratorId()->unqualifiedName()->text().trimmed(); if (m_thread) { m_thread->emitMessageToLog(QString(), QLatin1String("method ") + id); } uDebug() << id; UMLClassifier *c = m_currentClass[m_clsCnt]; if (c == NULL) { uDebug() << id << ": need a surrounding class."; return; } QString returnType = typeOfDeclaration(typeSpec, d); UMLOperation *m = Import_Utils::makeOperation(c, id); // if a class has no return type, it could be a constructor or // a destructor if (d && returnType.isEmpty() && id.indexOf(QLatin1Char('~')) == -1) isConstructor = true; parseFunctionArguments(d, m); Import_Utils::insertMethod(c, m, m_currentAccess, returnType, isStatic, false /*isAbstract*/, isFriend, isConstructor, m_comment); m_comment = QString(); /* For reference, Kdevelop does some more: method->setFileName(m_fileName); if (m_inSignals) method->setSignal(true); if (m_inSlots) method->setSlot(true); */ }
void CppTree2Uml::parseTypedef(TypedefAST* ast) { TypeSpecifierAST* typeSpec = ast->typeSpec(); InitDeclaratorListAST* declarators = ast->initDeclaratorList(); if (typeSpec && declarators){ QString typeId; if (typeSpec->name()) typeId = typeSpec->name()->text(); QList<InitDeclaratorAST*> l(declarators->initDeclaratorList()); InitDeclaratorAST* initDecl = 0; for (int i = 0; i < l.size(); ++i) { initDecl = l.at(i); if (initDecl==0) break; QString type, id; if (initDecl->declarator()){ type = typeOfDeclaration(typeSpec, initDecl->declarator()); DeclaratorAST* d = initDecl->declarator(); while (d->subDeclarator()){ d = d->subDeclarator(); } if (d->declaratorId()) id = d->declaratorId()->text(); } /* @todo Trace typedefs back to their root type for deciding whether to build a Datatype (for pointers.) */ /* check out if the ID type is a Datatype ex: typedef unsigned int uint; where unsigned int is a known datatype I'm not sure if setIsReference() should be run */ bool isDatatype = Import_Utils::isDatatype(typeId, m_currentNamespace[m_nsCnt]); if (type.contains(QLatin1Char('*')) || isDatatype) { UMLObject *inner = 0; if (m_currentNamespace[m_nsCnt] && m_currentNamespace[m_nsCnt]->baseType() == UMLObject::ot_Class && typeId == m_currentNamespace[m_nsCnt]->name()) inner = m_currentNamespace[m_nsCnt]; else inner = Import_Utils::createUMLObject(UMLObject::ot_Class, typeId, m_currentNamespace[m_nsCnt]); UMLObject *typedefObj = Import_Utils::createUMLObject(UMLObject::ot_Datatype, id, m_currentNamespace[m_nsCnt]); UMLClassifier *dt = static_cast<UMLClassifier*>(typedefObj); dt->setIsReference(); dt->setOriginType(static_cast<UMLClassifier*>(inner)); } else { Import_Utils::createUMLObject(UMLObject::ot_Class, id, m_currentNamespace[m_nsCnt], QString() /* doc */, QLatin1String("typedef") /* stereotype */); } } } }