diff options
author | Roberto Raggi <roberto.raggi@nokia.com> | 2010-08-03 17:34:51 +0200 |
---|---|---|
committer | Roberto Raggi <roberto.raggi@nokia.com> | 2010-08-03 17:35:02 +0200 |
commit | 1932ffd1c6615ee2c268d213a40d4f60caa6f2eb (patch) | |
tree | 2a21cce23d07f80213ad3a2c5c49009b70402273 /src/plugins/cppeditor/cppchecksymbols.cpp | |
parent | 221cc387887eb77e2367a6927330fd4b28c94a19 (diff) | |
download | qt-creator-1932ffd1c6615ee2c268d213a40d4f60caa6f2eb.tar.gz |
Highlight the virtual methods.
Diffstat (limited to 'src/plugins/cppeditor/cppchecksymbols.cpp')
-rw-r--r-- | src/plugins/cppeditor/cppchecksymbols.cpp | 188 |
1 files changed, 184 insertions, 4 deletions
diff --git a/src/plugins/cppeditor/cppchecksymbols.cpp b/src/plugins/cppeditor/cppchecksymbols.cpp index 27126be286..b7b95d8b93 100644 --- a/src/plugins/cppeditor/cppchecksymbols.cpp +++ b/src/plugins/cppeditor/cppchecksymbols.cpp @@ -63,6 +63,7 @@ class CollectTypes: protected SymbolVisitor Snapshot _snapshot; QSet<QByteArray> _types; QSet<QByteArray> _members; + QSet<QByteArray> _virtualMethods; QList<ScopedSymbol *> _scopes; QList<NameAST *> _names; bool _mainDocument; @@ -85,6 +86,11 @@ public: return _members; } + const QSet<QByteArray> &virtualMethods() const + { + return _virtualMethods; + } + const QList<ScopedSymbol *> &scopes() const { return _scopes; @@ -153,6 +159,18 @@ protected: } } + void addVirtualMethod(const Name *name) + { + if (! name) { + return; + + } else if (name->isNameId()) { + const Identifier *id = name->identifier(); + _virtualMethods.insert(QByteArray::fromRawData(id->chars(), id->size())); + + } + } + void addScope(ScopedSymbol *symbol) { if (_mainDocument) @@ -167,6 +185,9 @@ protected: virtual bool visit(Function *symbol) { + if (symbol->isVirtual()) + addVirtualMethod(symbol->name()); + for (TemplateParameters *p = symbol->templateParameters(); p; p = p->previous()) { Scope *scope = p->scope(); for (unsigned i = 0; i < scope->symbolCount(); ++i) @@ -191,6 +212,11 @@ protected: virtual bool visit(Declaration *symbol) { + if (Function *funTy = symbol->type()->asFunctionType()) { + if (funTy->isVirtual()) + addVirtualMethod(symbol->name()); + } + if (symbol->isTypedef()) addType(symbol->name()); else if (! symbol->type()->isFunctionType() && symbol->enclosingSymbol()->isClass()) @@ -298,6 +324,7 @@ CheckSymbols::CheckSymbols(Document::Ptr doc, const LookupContext &context) CollectTypes collectTypes(doc, context.snapshot()); _potentialTypes = collectTypes.types(); _potentialMembers = collectTypes.members(); + _potentialVirtualMethods = collectTypes.virtualMethods(); _scopes = collectTypes.scopes(); _flushRequested = false; _flushLine = 0; @@ -370,8 +397,23 @@ bool CheckSymbols::visit(UsingDirectiveAST *) return true; } -bool CheckSymbols::visit(SimpleDeclarationAST *) -{ +bool CheckSymbols::visit(SimpleDeclarationAST *ast) +{ + if (ast->declarator_list && !ast->declarator_list->next) { + if (ast->symbols && ! ast->symbols->next && !ast->symbols->value->isGenerated()) { + Symbol *decl = ast->symbols->value; + if (NameAST *declId = declaratorId(ast->declarator_list->value)) { + if (Function *funTy = decl->type()->asFunctionType()) { + if (funTy->isVirtual()) { + addVirtualMethodUsage(declId); + } else if (maybeVirtualMethod(decl->name())) { + addVirtualMethodUsage(_context.lookup(decl->name(), decl->scope()), declId, funTy->argumentCount()); + } + } + } + } + } + return true; } @@ -405,6 +447,52 @@ bool CheckSymbols::visit(MemberAccessAST *ast) return false; } +bool CheckSymbols::visit(CallAST *ast) +{ + if (ast->base_expression) { + accept(ast->base_expression); + + unsigned argumentCount = 0; + + for (ExpressionListAST *it = ast->expression_list; it; it = it->next) + ++argumentCount; + + if (MemberAccessAST *access = ast->base_expression->asMemberAccess()) { + if (access->member_name && access->member_name->name) { + if (maybeVirtualMethod(access->member_name->name)) { + Scope *scope = findScope(access); + const QByteArray expression = textOf(access); + + const QList<LookupItem> candidates = typeOfExpression(expression, scope, TypeOfExpression::Preprocess); + addVirtualMethodUsage(candidates, access->member_name, argumentCount); + } + } + } else if (IdExpressionAST *idExpr = ast->base_expression->asIdExpression()) { + if (const Name *name = idExpr->name->name) { + if (maybeVirtualMethod(name)) { + Scope *scope = findScope(idExpr); + const QByteArray expression = textOf(idExpr); + + const QList<LookupItem> candidates = typeOfExpression(expression, scope, TypeOfExpression::Preprocess); + addVirtualMethodUsage(candidates, idExpr->name, argumentCount); + } + } + } + + accept(ast->expression_list); + } + + return false; +} + +QByteArray CheckSymbols::textOf(AST *ast) const +{ + const Token start = tokenAt(ast->firstToken()); + const Token end = tokenAt(ast->lastToken() - 1); + const QByteArray text = _doc->source().mid(start.begin(), end.end() - start.begin()); + return text; +} + void CheckSymbols::checkNamespace(NameAST *name) { if (! name) @@ -573,6 +661,21 @@ bool CheckSymbols::visit(FunctionDefinitionAST *ast) _functionDefinitionStack.append(ast); accept(ast->decl_specifier_list); + + if (ast->declarator && ! ast->symbol->isGenerated()) { + Function *fun = ast->symbol; + if (NameAST *declId = declaratorId(ast->declarator)) { + if (QualifiedNameAST *q = declId->asQualifiedName()) + declId = q->unqualified_name; + + if (fun->isVirtual()) { + addVirtualMethodUsage(declId); + } else if (maybeVirtualMethod(fun->name())) { + addVirtualMethodUsage(_context.lookup(fun->name(), fun->scope()), declId, fun->argumentCount()); + } + } + } + accept(ast->declarator); accept(ast->ctor_initializer); accept(ast->function_body); @@ -687,8 +790,61 @@ void CheckSymbols::addMemberUsage(const QList<LookupItem> &candidates, NameAST * const Use use(line, column, length, Use::Field); addUsage(use); - //Overview oo; - //qDebug() << "added use" << oo(ast->name) << line << column << length; + break; + } +} + +void CheckSymbols::addVirtualMethodUsage(NameAST *ast) +{ + if (! ast) + return; + + unsigned startToken = ast->firstToken(); + if (DestructorNameAST *dtor = ast->asDestructorName()) + startToken = dtor->identifier_token; + + const Token &tok = tokenAt(startToken); + if (tok.generated()) + return; + + unsigned line, column; + getTokenStartPosition(startToken, &line, &column); + const unsigned length = tok.length(); + + const Use use(line, column, length, Use::VirtualMethod); + addUsage(use); +} + +void CheckSymbols::addVirtualMethodUsage(const QList<LookupItem> &candidates, NameAST *ast, unsigned argumentCount) +{ + unsigned startToken = ast->firstToken(); + if (DestructorNameAST *dtor = ast->asDestructorName()) + startToken = dtor->identifier_token; + + const Token &tok = tokenAt(startToken); + if (tok.generated()) + return; + + unsigned line, column; + getTokenStartPosition(startToken, &line, &column); + const unsigned length = tok.length(); + + foreach (const LookupItem &r, candidates) { + Symbol *c = r.declaration(); + if (! c) + continue; + + Function *funTy = r.type()->asFunctionType(); + if (! funTy) + continue; + if (! funTy->isVirtual()) + continue; + else if (argumentCount < funTy->minimumArgumentCount()) + continue; + + const Use use(line, column, length, Use::VirtualMethod); + addUsage(use); + break; } } @@ -723,6 +879,30 @@ Scope *CheckSymbols::findScope(AST *ast) const return scope; } +NameAST *CheckSymbols::declaratorId(DeclaratorAST *ast) const +{ + if (ast && ast->core_declarator) { + if (NestedDeclaratorAST *nested = ast->core_declarator->asNestedDeclarator()) + return declaratorId(nested->declarator); + else if (DeclaratorIdAST *declId = ast->core_declarator->asDeclaratorId()) { + return declId->name; + } + } + + return 0; +} + +bool CheckSymbols::maybeVirtualMethod(const Name *name) const +{ + if (const Identifier *ident = name->identifier()) { + const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size()); + if (_potentialVirtualMethods.contains(id)) + return true; + } + + return false; +} + void CheckSymbols::flush() { _flushRequested = false; |