📄 semantic.cpp
字号:
//look up an unqualified nameQList<CodeModel::Member *> Semantic::unqualifiedNameLookup(CodeModel::Scope *baseScope, const NameAST* name){ QList<UsingDirectiveLink *> usingDirectiveLinks; CodeModel::Scope *currentScope = baseScope; QList<CodeModel::Member *> entities; while (currentScope != 0) { // Add any "using namespace" directive links for the current scope to // usingDirectiveLinks if (NamespaceScope *namespaceScope = currentScope->toNamespaceScope()) usingDirectiveLinks += namespaceScope->usingDirectiveLinks(); if (BlockScope *blockScope = currentScope->toBlockScope()) usingDirectiveLinks += blockScope->usingDirectiveLinks(); // Search usingDirectiveLinks for a link where currentScope is the // insertion namespace. If found look up name in the target namespace // for that link. if (NamespaceScope *namespaceScope = currentScope->toNamespaceScope()) { QList<UsingDirectiveLink *>::ConstIterator it = usingDirectiveLinks.constBegin(); while (it != usingDirectiveLinks.constEnd()) { if ((*it)->insertionNamespace() == namespaceScope) entities = lookupNameInScope((*it)->targetNamespace(), name); ++it; } } // Look up names in this scope. entities += lookupNameInScope(currentScope, name); if (!entities.isEmpty()) break; currentScope = currentScope->parent(); } return entities;}//look up a qualified nameQList<CodeModel::Member *> Semantic::qualifiedNameLookup(CodeModel::Scope *baseScope, const NameAST* name){ QList<CodeModel::Member *> entities; CodeModel::Scope *currentScope = baseScope; // Check if the global ("::") scope has been specified. if(name->isGlobal()) { while (currentScope->parent()) currentScope = currentScope->parent(); } while (entities.isEmpty() && currentScope != 0) { CodeModel::Scope *targetScope = scopeLookup(currentScope, name); entities = lookupNameInScope(targetScope, name); currentScope = currentScope->parent(); } return entities;}//looks up a name in a scope, includes base classes if scope is a class scopeQList<CodeModel::Member *> Semantic::lookupNameInScope(CodeModel::Scope *scope, const NameAST* name){ QList<CodeModel::Member *> entities; if(!scope || !name) return entities; QByteArray nameText = textOf(name->unqualifiedName()->name()); //look up name in members of current scope const CodeModel::MemberCollection members = scope->members(); if (members.contains(nameText)) entities.append(members.value(nameText)); // if not found, look up name in base classes (if any) CodeModel::ClassScope *classScope = scope->toClassScope(); if (entities.isEmpty() && classScope) { const TypeCollection baseClasses = classScope->baseClasses(); TypeCollection::ConstIterator it = baseClasses.constBegin(); while (it != baseClasses.constEnd()) { CodeModel::Scope *baseClass = it.value()->toClassType()->scope(); if (scope != baseClass) entities += lookupNameInScope(baseClass, name); ++it; } if (entities.count() > 1) emit error("Error in Semantic::lookupNameInScope: name " + nameText + " is ambigous"); } return entities;}/* Resolves the classOrNamespaceNameList part of a NameAST against a base scope.*/CodeModel::Scope *Semantic::scopeLookup(CodeModel::Scope *baseScope, const NameAST* name){ CodeModel::Scope *currentScope = baseScope; const List<ClassOrNamespaceNameAST *> *scopeList = name->classOrNamespaceNameList(); // if there is no scope list, then the scope we are looking for is baseScope if (!scopeList) return baseScope; // Check if the global ("::") scope has been specified. if(name->isGlobal()) { while (currentScope->parent()) currentScope = currentScope->parent(); } while(currentScope != 0) { int nestingCounter = 0; CodeModel::Scope *nestedScope = currentScope; while (nestingCounter < scopeList->count()) { const QByteArray nameText = textOf((*scopeList)[nestingCounter]->name()); nestedScope = nestedScope->scopes().value(nameText); if (!nestedScope) break; ++nestingCounter; } if(nestedScope) // found target scope? return nestedScope; currentScope = currentScope->parent(); //look in parent scope } return 0;}TypeMember *Semantic::typeLookup(CodeModel::Scope *baseScope, const NameAST* name){ QList<CodeModel::Member *> memberList = nameLookup(baseScope, name); foreach(Member *member, memberList) { if(TypeMember *typeMember = member->toTypeMember()) return typeMember; } return 0;}FunctionMember *Semantic::functionLookup(CodeModel::Scope *baseScope, const DeclaratorAST *functionDeclarator){ QList<CodeModel::Member*> candidateList = nameLookup(baseScope, functionDeclarator->declaratorId()); return selectFunction(candidateList, functionDeclarator);}/* This is a simplified function lookup routine, for matching member function definitions with member function declarations. It does not implement the general C++ function overload resolution rules.*/FunctionMember *Semantic::selectFunction(QList<CodeModel::Member*> candidatateList, const DeclaratorAST *functionDeclarator){ // get arguments for funciton we are looking for FunctionMember testFunction; parseFunctionArguments(functionDeclarator, &testFunction); const ArgumentCollection testArgumentCollection = testFunction.arguments(); //test againts functions in overload list. foreach(Member* member, candidatateList) { FunctionMember *function = member->toFunctionMember(); if (!function) continue; const ArgumentCollection argumentCollection = function->arguments(); //test argument types and number of arguments ArgumentCollection::ConstIterator arg1 = argumentCollection.constBegin(); ArgumentCollection::ConstIterator arg2 = testArgumentCollection.constBegin(); bool match = true; while(arg1 != argumentCollection.constEnd() && arg2 != testArgumentCollection.constEnd()) { if( arg1.value()->type()->name() != arg2.value()->type()->name() ) { match = false; break; } ++arg1; ++arg2; } if(match) return function; } return 0;}QByteArray Semantic::typeOfDeclaration(TypeSpecifierAST *typeSpec, DeclaratorAST *declarator){ if (!typeSpec) return QByteArray(); QByteArray text; if (typeSpec->cvQualify()) { List<AST*> cv = *typeSpec->cvQualify()->children(); foreach (AST *current, cv) { text += " " + textOf(current); } text += " "; } text += textOf(typeSpec); if (typeSpec->cv2Qualify()) { List<AST*> cv = *typeSpec->cv2Qualify()->children(); foreach (AST *current, cv) { text += textOf(current) + " "; } } if (declarator && declarator->ptrOpList()) { List<AST*> ptrOpList = *declarator->ptrOpList(); foreach (AST *current, ptrOpList) { text += " " + textOf(current); } text += " "; } return text.trimmed().simplified();}QList<QByteArray> Semantic::scopeOfName(NameAST *id, const QList<QByteArray>& startScope){ QList<QByteArray> scope = startScope; if (id && id->classOrNamespaceNameList()){ if (id->isGlobal()) scope.clear(); List<ClassOrNamespaceNameAST*> l = *id->classOrNamespaceNameList(); foreach (ClassOrNamespaceNameAST *current, l) { if (current->name()) scope << textOf(current->name()); } } return scope;}QList<QByteArray> Semantic::scopeOfDeclarator(DeclaratorAST *d, const QList<QByteArray>& startScope){ if(!d) return QList<QByteArray>(); return scopeOfName(d->declaratorId(), startScope);}QByteArray Semantic::typeSpecToString(TypeSpecifierAST* typeSpec){ if (!typeSpec) return QByteArray(); QByteArray tp; if (typeSpec->cvQualify()) { tp += "const "; } tp += (QString(textOf(typeSpec)).replace(QRegExp(" :: "), QString::fromUtf8("::"))).toLatin1(); return tp;}QByteArray Semantic::declaratorToString(DeclaratorAST* declarator, const QByteArray& scope, bool skipPtrOp){ if (!declarator) return QByteArray(); QByteArray text; if (!skipPtrOp && declarator->ptrOpList()){ List<AST*> ptrOpList = *declarator->ptrOpList(); foreach (AST *current, ptrOpList) { text += textOf(current); } text += " "; } text += scope; if (declarator->subDeclarator()) text += "(" + declaratorToString(declarator->subDeclarator()) + ")"; if (declarator->declaratorId()) text += textOf(declarator->declaratorId()); if (declarator->arrayDimensionList()) { List<AST*> arrays = *declarator->arrayDimensionList(); foreach (AST *current, arrays) { current=current; //silence unused symbol warning text += "[]"; } } if (declarator->parameterDeclarationClause()){ text += "("; ParameterDeclarationListAST* l = declarator->parameterDeclarationClause()->parameterDeclarationList(); if (l != 0){ List<ParameterDeclarationAST*> params = *l->parameterList(); foreach (ParameterDeclarationAST *current, params) { QByteArray type = typeSpecToString(current->typeSpec()); text += type; if (!type.isEmpty()) text += " "; text += declaratorToString(current->declarator()); // ### FIXME if (it.current()) text += ", "; } } text += ")"; if (declarator->constant() != 0) text += " const"; } return QString(text).replace(QRegExp(" :: "), "::").simplified().toLatin1();}QByteArray Semantic::textOf(const AST *node) const{ if (!node) return QByteArray(); QByteArray text; for (int i = node->startToken(); i < node->endToken(); ++i) { if (!m_tokenStream->isHidden(i)) { if (i != node->startToken()) text += " "; text += m_tokenStream->tokenText(i); } } return text;}void Semantic::createNameUse(Member *member, NameAST *name){ if (!name) return; AST *unqualifedName = name->unqualifiedName()->name(); if(!unqualifedName || !member) return; CodeModel::NameUse *nameUse = CodeModel::Create<CodeModel::NameUse>(m_storage); nameUse->setParent(currentScope.top()); nameUse->setNameToken(tokenRefFromAST(unqualifedName)); nameUse->setName(textOf(unqualifedName)); nameUse->setDeclaration(member); currentScope.top()->addNameUse(nameUse); addNameUse(unqualifedName, nameUse);}void Semantic::addNameUse(AST *node, NameUse *nameUse){ const int tokenIndex = node->startToken(); m_nameUses.insert(tokenIndex, nameUse);}/* Searches a AST node and all its children for a nameUse. The name use is found by looking up each node's tokens in the m_nameUses map. A depth-first search is used.*/NameUse *Semantic::findNameUse(AST *node){ if(!node) return 0; List<AST*> *children = node->children(); if(children) { NameUse *nameUse = 0; foreach(AST* child , *children) { nameUse = findNameUse(child); if(nameUse) break; } if (nameUse) return nameUse; } for (int t = node->startToken(); t < node->endToken(); ++t) { // cout << t <<" |" <<m_tokenStream->tokenText(t).constData() << "|" << endl; if (m_nameUses.contains(t)) return m_nameUses.value(t); } return 0;}/* Gets a TokenRef from an AST node. Assumes that the node only covers one token, which means that node->statToken() == node->endToken(). If this is not the case then the TokenRef will reference the token at startToken.*/TokenEngine::TokenRef Semantic::tokenRefFromAST(AST *node){ const int startTokenIndex = node->startToken(); const TokenEngine::TokenContainer tokenContainer = m_tokenStream->tokenContainer(startTokenIndex); const int containerIndex = m_tokenStream->containerIndex(startTokenIndex); return TokenEngine::TokenRef(tokenContainer, containerIndex);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -