From dbc3332b8e1442c0903e129586c08986ce752ff9 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Tue, 7 Feb 2012 15:09:08 +0100 Subject: C++: Moved completion/highlighting into the model manager. This way the editor does not need to know all the details of instantiating or maintaining classes for highlighting and/or completion, it can just ask the model manager. The change also enables different highlighting- or completion-engines without changes to the cppeditor. Change-Id: I8000d9d9fe446b292defddb2295493cf77d0f14a Reviewed-by: Leandro Melo --- src/plugins/cppeditor/cppchecksymbols.cpp | 1110 ---------------------- src/plugins/cppeditor/cppchecksymbols.h | 176 ---- src/plugins/cppeditor/cppeditor.cpp | 42 +- src/plugins/cppeditor/cppeditor.h | 24 +- src/plugins/cppeditor/cppeditor.pro | 6 - src/plugins/cppeditor/cppfunctiondecldeflink.cpp | 3 +- src/plugins/cppeditor/cpplocalsymbols.cpp | 302 ------ src/plugins/cppeditor/cpplocalsymbols.h | 58 -- src/plugins/cppeditor/cppquickfixassistant.h | 6 +- src/plugins/cppeditor/cppsemanticinfo.cpp | 40 - src/plugins/cppeditor/cppsemanticinfo.h | 76 -- src/plugins/cpptools/cppchecksymbols.cpp | 1110 ++++++++++++++++++++++ src/plugins/cpptools/cppchecksymbols.h | 178 ++++ src/plugins/cpptools/cppcompletionsupport.cpp | 72 ++ src/plugins/cpptools/cppcompletionsupport.h | 77 ++ src/plugins/cpptools/cpphighlightingsupport.cpp | 52 + src/plugins/cpptools/cpphighlightingsupport.h | 62 ++ src/plugins/cpptools/cpplocalsymbols.cpp | 302 ++++++ src/plugins/cpptools/cpplocalsymbols.h | 58 ++ src/plugins/cpptools/cppmodelmanager.cpp | 15 + src/plugins/cpptools/cppmodelmanager.h | 4 +- src/plugins/cpptools/cppsemanticinfo.cpp | 40 + src/plugins/cpptools/cppsemanticinfo.h | 74 ++ src/plugins/cpptools/cpptools.pro | 14 +- src/plugins/cpptools/cpptoolseditorsupport.cpp | 17 +- src/plugins/cpptools/cpptoolseditorsupport.h | 10 + 26 files changed, 2114 insertions(+), 1814 deletions(-) delete mode 100644 src/plugins/cppeditor/cppchecksymbols.cpp delete mode 100644 src/plugins/cppeditor/cppchecksymbols.h delete mode 100644 src/plugins/cppeditor/cpplocalsymbols.cpp delete mode 100644 src/plugins/cppeditor/cpplocalsymbols.h delete mode 100644 src/plugins/cppeditor/cppsemanticinfo.cpp delete mode 100644 src/plugins/cppeditor/cppsemanticinfo.h create mode 100644 src/plugins/cpptools/cppchecksymbols.cpp create mode 100644 src/plugins/cpptools/cppchecksymbols.h create mode 100644 src/plugins/cpptools/cppcompletionsupport.cpp create mode 100644 src/plugins/cpptools/cppcompletionsupport.h create mode 100644 src/plugins/cpptools/cpphighlightingsupport.cpp create mode 100644 src/plugins/cpptools/cpphighlightingsupport.h create mode 100644 src/plugins/cpptools/cpplocalsymbols.cpp create mode 100644 src/plugins/cpptools/cpplocalsymbols.h create mode 100644 src/plugins/cpptools/cppsemanticinfo.cpp create mode 100644 src/plugins/cpptools/cppsemanticinfo.h (limited to 'src/plugins') diff --git a/src/plugins/cppeditor/cppchecksymbols.cpp b/src/plugins/cppeditor/cppchecksymbols.cpp deleted file mode 100644 index a5749445a5..0000000000 --- a/src/plugins/cppeditor/cppchecksymbols.cpp +++ /dev/null @@ -1,1110 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** -** GNU Lesser General Public License Usage -** -** 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. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cppchecksymbols.h" -#include "cpplocalsymbols.h" - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include - -using namespace CPlusPlus; -using namespace CppEditor::Internal; - -namespace { - -class FriendlyThread: public QThread -{ -public: - using QThread::msleep; -}; - -class CollectSymbols: protected SymbolVisitor -{ - Document::Ptr _doc; - Snapshot _snapshot; - QSet _types; - QSet _members; - QSet _virtualMethods; - QSet _statics; - bool _mainDocument; - -public: - CollectSymbols(Document::Ptr doc, const Snapshot &snapshot) - : _doc(doc), _snapshot(snapshot), _mainDocument(false) - { - QSet processed; - process(doc, &processed); - } - - const QSet &types() const - { - return _types; - } - - const QSet &members() const - { - return _members; - } - - const QSet &virtualMethods() const - { - return _virtualMethods; - } - - const QSet &statics() const - { - return _statics; - } - -protected: - void process(Document::Ptr doc, QSet *processed) - { - if (! doc) - return; - else if (! processed->contains(doc->globalNamespace())) { - processed->insert(doc->globalNamespace()); - - foreach (const Document::Include &i, doc->includes()) - process(_snapshot.document(i.fileName()), processed); - - _mainDocument = (doc == _doc); // ### improve - accept(doc->globalNamespace()); - } - } - - void addType(const Identifier *id) - { - if (id) - _types.insert(QByteArray::fromRawData(id->chars(), id->size())); - } - - void addType(const Name *name) - { - if (! name) { - return; - - } else if (const QualifiedNameId *q = name->asQualifiedNameId()) { - addType(q->base()); - addType(q->name()); - - } else if (name->isNameId() || name->isTemplateNameId()) { - addType(name->identifier()); - - } - } - - void addMember(const Name *name) - { - if (! name) { - return; - - } else if (name->isNameId()) { - const Identifier *id = name->identifier(); - _members.insert(QByteArray::fromRawData(id->chars(), id->size())); - - } - } - - 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 addStatic(const Name *name) - { - if (! name) { - return; - - } else if (name->isNameId() || name->isTemplateNameId()) { - const Identifier *id = name->identifier(); - _statics.insert(QByteArray::fromRawData(id->chars(), id->size())); - - } - } - - // nothing to do - virtual bool visit(UsingNamespaceDirective *) { return true; } - virtual bool visit(UsingDeclaration *) { return true; } - virtual bool visit(Argument *) { return true; } - virtual bool visit(BaseClass *) { return true; } - - virtual bool visit(Function *symbol) - { - if (symbol->isVirtual()) - addVirtualMethod(symbol->name()); - - return true; - } - - virtual bool visit(Block *) - { - return true; - } - - virtual bool visit(NamespaceAlias *symbol) - { - addType(symbol->name()); - return true; - } - - virtual bool visit(Declaration *symbol) - { - if (symbol->enclosingEnum() != 0) - addStatic(symbol->name()); - - if (Function *funTy = symbol->type()->asFunctionType()) { - if (funTy->isVirtual()) - addVirtualMethod(symbol->name()); - } - - if (symbol->isTypedef()) - addType(symbol->name()); - else if (! symbol->type()->isFunctionType() && symbol->enclosingScope()->isClass()) - addMember(symbol->name()); - - return true; - } - - virtual bool visit(TypenameArgument *symbol) - { - addType(symbol->name()); - return true; - } - - virtual bool visit(Enum *symbol) - { - addType(symbol->name()); - return true; - } - - virtual bool visit(Namespace *symbol) - { - addType(symbol->name()); - return true; - } - - virtual bool visit(Template *) - { - return true; - } - - virtual bool visit(Class *symbol) - { - addType(symbol->name()); - return true; - } - - virtual bool visit(ForwardClassDeclaration *symbol) - { - addType(symbol->name()); - return true; - } - - // Objective-C - virtual bool visit(ObjCBaseClass *) { return true; } - virtual bool visit(ObjCBaseProtocol *) { return true; } - virtual bool visit(ObjCPropertyDeclaration *) { return true; } - virtual bool visit(ObjCMethod *) { return true; } - - virtual bool visit(ObjCClass *symbol) - { - addType(symbol->name()); - return true; - } - - virtual bool visit(ObjCForwardClassDeclaration *symbol) - { - addType(symbol->name()); - return true; - } - - virtual bool visit(ObjCProtocol *symbol) - { - addType(symbol->name()); - return true; - } - - virtual bool visit(ObjCForwardProtocolDeclaration *symbol) - { - addType(symbol->name()); - return true; - } -}; - -} // end of anonymous namespace - -CheckSymbols::Future CheckSymbols::go(Document::Ptr doc, const LookupContext &context) -{ - QTC_ASSERT(doc, return Future()); - - return (new CheckSymbols(doc, context))->start(); -} - -CheckSymbols::CheckSymbols(Document::Ptr doc, const LookupContext &context) - : ASTVisitor(doc->translationUnit()), _doc(doc), _context(context) - , _lineOfLastUsage(0) -{ - CollectSymbols collectTypes(doc, context.snapshot()); - - _fileName = doc->fileName(); - _potentialTypes = collectTypes.types(); - _potentialMembers = collectTypes.members(); - _potentialVirtualMethods = collectTypes.virtualMethods(); - _potentialStatics = collectTypes.statics(); - - typeOfExpression.init(_doc, _context.snapshot(), _context.bindings()); -} - -CheckSymbols::~CheckSymbols() -{ } - -void CheckSymbols::run() -{ - _diagnosticMessages.clear(); - - if (! isCanceled()) { - if (_doc->translationUnit()) { - accept(_doc->translationUnit()->ast()); - flush(); - } - } - - reportFinished(); -} - -bool CheckSymbols::warning(unsigned line, unsigned column, const QString &text, unsigned length) -{ - Document::DiagnosticMessage m(Document::DiagnosticMessage::Warning, _fileName, line, column, text, length); - _diagnosticMessages.append(m); - return false; -} - -bool CheckSymbols::warning(AST *ast, const QString &text) -{ - const Token &firstToken = tokenAt(ast->firstToken()); - const Token &lastToken = tokenAt(ast->lastToken() - 1); - - const unsigned length = lastToken.end() - firstToken.begin(); - unsigned line = 1, column = 1; - getTokenStartPosition(ast->firstToken(), &line, &column); - - warning(line, column, text, length); - return false; -} - -FunctionDefinitionAST *CheckSymbols::enclosingFunctionDefinition(bool skipTopOfStack) const -{ - int index = _astStack.size() - 1; - if (skipTopOfStack && !_astStack.isEmpty()) - --index; - for (; index != -1; --index) { - AST *ast = _astStack.at(index); - - if (FunctionDefinitionAST *funDef = ast->asFunctionDefinition()) - return funDef; - } - - return 0; -} - -TemplateDeclarationAST *CheckSymbols::enclosingTemplateDeclaration() const -{ - for (int index = _astStack.size() - 1; index != -1; --index) { - AST *ast = _astStack.at(index); - - if (TemplateDeclarationAST *funDef = ast->asTemplateDeclaration()) - return funDef; - } - - return 0; -} - -Scope *CheckSymbols::enclosingScope() const -{ - for (int index = _astStack.size() - 1; index != -1; --index) { - AST *ast = _astStack.at(index); - - if (NamespaceAST *ns = ast->asNamespace()) { - if (ns->symbol) - return ns->symbol; - - } else if (ClassSpecifierAST *classSpec = ast->asClassSpecifier()) { - if (classSpec->symbol) - return classSpec->symbol; - - } else if (FunctionDefinitionAST *funDef = ast->asFunctionDefinition()) { - if (funDef->symbol) - return funDef->symbol; - - } else if (CompoundStatementAST *blockStmt = ast->asCompoundStatement()) { - if (blockStmt->symbol) - return blockStmt->symbol; - - } else if (IfStatementAST *ifStmt = ast->asIfStatement()) { - if (ifStmt->symbol) - return ifStmt->symbol; - - } else if (WhileStatementAST *whileStmt = ast->asWhileStatement()) { - if (whileStmt->symbol) - return whileStmt->symbol; - - } else if (ForStatementAST *forStmt = ast->asForStatement()) { - if (forStmt->symbol) - return forStmt->symbol; - - } else if (ForeachStatementAST *foreachStmt = ast->asForeachStatement()) { - if (foreachStmt->symbol) - return foreachStmt->symbol; - - } else if (SwitchStatementAST *switchStmt = ast->asSwitchStatement()) { - if (switchStmt->symbol) - return switchStmt->symbol; - - } else if (CatchClauseAST *catchClause = ast->asCatchClause()) { - if (catchClause->symbol) - return catchClause->symbol; - - } - } - - return _doc->globalNamespace(); -} - -bool CheckSymbols::preVisit(AST *ast) -{ - _astStack.append(ast); - - if (isCanceled()) - return false; - - return true; -} - -void CheckSymbols::postVisit(AST *) -{ - _astStack.takeLast(); -} - -bool CheckSymbols::visit(NamespaceAST *ast) -{ - if (ast->identifier_token) { - const Token &tok = tokenAt(ast->identifier_token); - if (! tok.generated()) { - unsigned line, column; - getTokenStartPosition(ast->identifier_token, &line, &column); - Use use(line, column, tok.length(), SemanticInfo::TypeUse); - addUse(use); - } - } - - return true; -} - -bool CheckSymbols::visit(UsingDirectiveAST *) -{ - return true; -} - -bool CheckSymbols::visit(EnumeratorAST *ast) -{ - addUse(ast->identifier_token, SemanticInfo::StaticUse); - return true; -} - -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()) { - addUse(declId, SemanticInfo::VirtualMethodUse); - } else if (maybeVirtualMethod(decl->name())) { - addVirtualMethod(_context.lookup(decl->name(), decl->enclosingScope()), declId, funTy->argumentCount()); - } - } - } - } - } - - return true; -} - -bool CheckSymbols::visit(NamedTypeSpecifierAST *) -{ - return true; -} - -bool CheckSymbols::visit(ElaboratedTypeSpecifierAST *ast) -{ - accept(ast->attribute_list); - accept(ast->name); - addUse(ast->name, SemanticInfo::TypeUse); - return false; -} - -bool CheckSymbols::visit(MemberAccessAST *ast) -{ - accept(ast->base_expression); - if (! ast->member_name) - return false; - - if (const Name *name = ast->member_name->name) { - if (const Identifier *ident = name->identifier()) { - const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size()); - if (_potentialMembers.contains(id)) { - const Token start = tokenAt(ast->firstToken()); - const Token end = tokenAt(ast->lastToken() - 1); - const QByteArray expression = _doc->utf8Source().mid(start.begin(), end.end() - start.begin()); - - const QList candidates = - typeOfExpression(expression, enclosingScope(), TypeOfExpression::Preprocess); - addClassMember(candidates, ast->member_name); - } - } - } - - 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)) { - const QByteArray expression = textOf(access); - - const QList candidates = - typeOfExpression(expression, enclosingScope(), - TypeOfExpression::Preprocess); - - NameAST *memberName = access->member_name; - if (QualifiedNameAST *q = memberName->asQualifiedName()) - memberName = q->unqualified_name; - - addVirtualMethod(candidates, memberName, argumentCount); - } - } - } else if (IdExpressionAST *idExpr = ast->base_expression->asIdExpression()) { - if (const Name *name = idExpr->name->name) { - if (maybeVirtualMethod(name)) { - NameAST *exprName = idExpr->name; - if (QualifiedNameAST *q = exprName->asQualifiedName()) - exprName = q->unqualified_name; - - const QList candidates = - typeOfExpression(textOf(idExpr), enclosingScope(), - TypeOfExpression::Preprocess); - addVirtualMethod(candidates, exprName, 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->utf8Source().mid(start.begin(), end.end() - start.begin()); - return text; -} - -void CheckSymbols::checkNamespace(NameAST *name) -{ - if (! name) - return; - - unsigned line, column; - getTokenStartPosition(name->firstToken(), &line, &column); - - if (ClassOrNamespace *b = _context.lookupType(name->name, enclosingScope())) { - foreach (Symbol *s, b->symbols()) { - if (s->isNamespace()) - return; - } - } - - const unsigned length = tokenAt(name->lastToken() - 1).end() - tokenAt(name->firstToken()).begin(); - warning(line, column, QCoreApplication::translate("CheckUndefinedSymbols", "Expected a namespace-name"), length); -} - -bool CheckSymbols::hasVirtualDestructor(Class *klass) const -{ - if (! klass) - return false; - const Identifier *id = klass->identifier(); - if (! id) - return false; - for (Symbol *s = klass->find(id); s; s = s->next()) { - if (! s->name()) - continue; - else if (s->name()->isDestructorNameId()) { - if (Function *funTy = s->type()->asFunctionType()) { - if (funTy->isVirtual() && id->isEqualTo(s->identifier())) - return true; - } - } - } - return false; -} - -bool CheckSymbols::hasVirtualDestructor(ClassOrNamespace *binding) const -{ - QSet processed; - QList todo; - todo.append(binding); - - while (! todo.isEmpty()) { - ClassOrNamespace *b = todo.takeFirst(); - if (b && ! processed.contains(b)) { - processed.insert(b); - foreach (Symbol *s, b->symbols()) { - if (Class *k = s->asClass()) { - if (hasVirtualDestructor(k)) - return true; - } - } - - todo += b->usings(); - } - } - - return false; -} - -void CheckSymbols::checkName(NameAST *ast, Scope *scope) -{ - if (ast && ast->name) { - if (! scope) - scope = enclosingScope(); - - if (ast->asDestructorName() != 0) { - Class *klass = scope->asClass(); - if (hasVirtualDestructor(_context.lookupType(klass))) - addUse(ast, SemanticInfo::VirtualMethodUse); - } else if (maybeType(ast->name) || maybeStatic(ast->name)) { - const QList candidates = _context.lookup(ast->name, scope); - addTypeOrStatic(candidates, ast); - } else if (maybeMember(ast->name)) { - const QList candidates = _context.lookup(ast->name, scope); - addClassMember(candidates, ast); - } - } -} - -bool CheckSymbols::visit(SimpleNameAST *ast) -{ - checkName(ast); - return true; -} - -bool CheckSymbols::visit(TemplateIdAST *ast) -{ - checkName(ast); - return true; -} - -bool CheckSymbols::visit(DestructorNameAST *ast) -{ - checkName(ast); - return true; -} - -bool CheckSymbols::visit(QualifiedNameAST *ast) -{ - if (ast->name) { - ClassOrNamespace *binding = 0; - if (NestedNameSpecifierListAST *it = ast->nested_name_specifier_list) { - NestedNameSpecifierAST *nested_name_specifier = it->value; - if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) { // ### remove shadowing - - if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId()) - accept(template_id->template_argument_list); - - const Name *name = class_or_namespace_name->name; - binding = _context.lookupType(name, enclosingScope()); - addType(binding, class_or_namespace_name); - - for (it = it->next; it; it = it->next) { - NestedNameSpecifierAST *nested_name_specifier = it->value; - - if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) { - if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId()) { - if (template_id->template_token) { - addUse(template_id, SemanticInfo::TypeUse); - binding = 0; // there's no way we can find a binding. - } - - accept(template_id->template_argument_list); - if (! binding) - continue; - } - - if (binding) { - binding = binding->findType(class_or_namespace_name->name); - addType(binding, class_or_namespace_name); - } - } - } - } - } - - if (binding && ast->unqualified_name) { - if (ast->unqualified_name->asDestructorName() != 0) { - if (hasVirtualDestructor(binding)) - addUse(ast->unqualified_name, SemanticInfo::VirtualMethodUse); - } else { - addTypeOrStatic(binding->find(ast->unqualified_name->name), ast->unqualified_name); - } - - if (TemplateIdAST *template_id = ast->unqualified_name->asTemplateId()) - accept(template_id->template_argument_list); - } - } - - return false; -} - -bool CheckSymbols::visit(TypenameTypeParameterAST *ast) -{ - addUse(ast->name, SemanticInfo::TypeUse); - accept(ast->type_id); - return false; -} - -bool CheckSymbols::visit(TemplateTypeParameterAST *ast) -{ - accept(ast->template_parameter_list); - addUse(ast->name, SemanticInfo::TypeUse); - accept(ast->type_id); - return false; -} - -bool CheckSymbols::visit(MemInitializerAST *ast) -{ - if (FunctionDefinitionAST *enclosingFunction = enclosingFunctionDefinition()) { - if (ast->name && enclosingFunction->symbol) { - if (ClassOrNamespace *binding = _context.lookupType(enclosingFunction->symbol)) { - foreach (Symbol *s, binding->symbols()) { - if (Class *klass = s->asClass()){ - checkName(ast->name, klass); - break; - } - } - } - } - - accept(ast->expression_list); - } - - return false; -} - -bool CheckSymbols::visit(FunctionDefinitionAST *ast) -{ - AST *thisFunction = _astStack.takeLast(); - accept(ast->decl_specifier_list); - _astStack.append(thisFunction); - - if (ast->declarator && ast->symbol && ! 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()) { - addUse(declId, SemanticInfo::VirtualMethodUse); - } else if (maybeVirtualMethod(fun->name())) { - addVirtualMethod(_context.lookup(fun->name(), fun->enclosingScope()), declId, fun->argumentCount()); - } - } - } - - accept(ast->declarator); - accept(ast->ctor_initializer); - accept(ast->function_body); - - const LocalSymbols locals(_doc, ast); - foreach (const QList &uses, locals.uses) { - foreach (const SemanticInfo::Use &u, uses) - addUse(u); - } - - if (!enclosingFunctionDefinition(true)) - flush(); - - return false; -} - -void CheckSymbols::addUse(NameAST *ast, UseKind kind) -{ - if (! ast) - return; - - if (QualifiedNameAST *q = ast->asQualifiedName()) - ast = q->unqualified_name; - - if (! ast) - return; // nothing to do - else if (ast->asOperatorFunctionId() != 0 || ast->asConversionFunctionId() != 0) - return; // nothing to do - - unsigned startToken = ast->firstToken(); - - if (DestructorNameAST *dtor = ast->asDestructorName()) - startToken = dtor->identifier_token; - - else if (TemplateIdAST *templ = ast->asTemplateId()) - startToken = templ->identifier_token; - - addUse(startToken, kind); -} - -void CheckSymbols::addUse(unsigned tokenIndex, UseKind kind) -{ - if (! tokenIndex) - return; - - const Token &tok = tokenAt(tokenIndex); - if (tok.generated()) - return; - - unsigned line, column; - getTokenStartPosition(tokenIndex, &line, &column); - const unsigned length = tok.length(); - - const Use use(line, column, length, kind); - addUse(use); -} - -static const int chunkSize = 50; - -void CheckSymbols::addUse(const Use &use) -{ - if (!use.line) - return; - - if (! enclosingFunctionDefinition()) { - if (_usages.size() >= chunkSize) { - if (use.line > _lineOfLastUsage) - flush(); - } - } - - _lineOfLastUsage = qMax(_lineOfLastUsage, use.line); - _usages.append(use); -} - -void CheckSymbols::addType(ClassOrNamespace *b, NameAST *ast) -{ - if (! b) - 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, SemanticInfo::TypeUse); - addUse(use); - //qDebug() << "added use" << oo(ast->name) << line << column << length; -} - -bool CheckSymbols::isTemplateClass(Symbol *symbol) const -{ - if (symbol) { - if (Template *templ = symbol->asTemplate()) { - if (Symbol *declaration = templ->declaration()) { - if (declaration->isClass() || declaration->isForwardClassDeclaration()) - return true; - } - } - } - return false; -} - -void CheckSymbols::addTypeOrStatic(const QList &candidates, NameAST *ast) -{ - unsigned startToken = ast->firstToken(); - if (DestructorNameAST *dtor = ast->asDestructorName()) - startToken = dtor->identifier_token; - - const Token &tok = tokenAt(startToken); - if (tok.generated()) - return; - - foreach (const LookupItem &r, candidates) { - Symbol *c = r.declaration(); - if (c->isUsingDeclaration()) // skip using declarations... - continue; - else if (c->isUsingNamespaceDirective()) // ... and using namespace directives. - continue; - else if (c->isTypedef() || c->isNamespace() || - c->isClass() || c->isEnum() || isTemplateClass(c) || - c->isForwardClassDeclaration() || c->isTypenameArgument() || c->enclosingEnum() != 0) { - - unsigned line, column; - getTokenStartPosition(startToken, &line, &column); - const unsigned length = tok.length(); - - UseKind kind = SemanticInfo::TypeUse; - - if (c->enclosingEnum() != 0) - kind = SemanticInfo::StaticUse; - - const Use use(line, column, length, kind); - addUse(use); - //qDebug() << "added use" << oo(ast->name) << line << column << length; - break; - } - } -} - -void CheckSymbols::addClassMember(const QList &candidates, NameAST *ast) -{ - unsigned startToken = ast->firstToken(); - if (DestructorNameAST *dtor = ast->asDestructorName()) - startToken = dtor->identifier_token; - - const Token &tok = tokenAt(startToken); - if (tok.generated()) - return; - - foreach (const LookupItem &r, candidates) { - Symbol *c = r.declaration(); - if (! c) - continue; - else if (! c->isDeclaration()) - return; - else if (! (c->enclosingScope() && c->enclosingScope()->isClass())) - return; // shadowed - else if (c->isTypedef() || c->type()->isFunctionType()) - return; // shadowed - - unsigned line, column; - getTokenStartPosition(startToken, &line, &column); - const unsigned length = tok.length(); - - const Use use(line, column, length, SemanticInfo::FieldUse); - addUse(use); - break; - } -} - -void CheckSymbols::addStatic(const QList &candidates, NameAST *ast) -{ - if (ast->asDestructorName() != 0) - return; - - unsigned startToken = ast->firstToken(); - const Token &tok = tokenAt(startToken); - if (tok.generated()) - return; - - foreach (const LookupItem &r, candidates) { - Symbol *c = r.declaration(); - if (! c) - return; - if (c->enclosingScope()->isEnum()) { - unsigned line, column; - getTokenStartPosition(startToken, &line, &column); - const unsigned length = tok.length(); - - const Use use(line, column, length, SemanticInfo::StaticUse); - addUse(use); - //qDebug() << "added use" << oo(ast->name) << line << column << length; - break; - } - } -} - -void CheckSymbols::addVirtualMethod(const QList &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; - - 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; - else if (argumentCount > funTy->argumentCount()) { - if (! funTy->isVariadic()) - continue; - } - - unsigned line, column; - getTokenStartPosition(startToken, &line, &column); - const unsigned length = tok.length(); - - const Use use(line, column, length, SemanticInfo::VirtualMethodUse); - addUse(use); - break; - } -} - -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::maybeType(const Name *name) const -{ - if (name) { - if (const Identifier *ident = name->identifier()) { - const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size()); - if (_potentialTypes.contains(id)) - return true; - } - } - - return false; -} - -bool CheckSymbols::maybeMember(const Name *name) const -{ - if (name) { - if (const Identifier *ident = name->identifier()) { - const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size()); - if (_potentialMembers.contains(id)) - return true; - } - } - - return false; -} - -bool CheckSymbols::maybeStatic(const Name *name) const -{ - if (name) { - if (const Identifier *ident = name->identifier()) { - const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size()); - if (_potentialStatics.contains(id)) - return true; - } - } - - return false; -} - -bool CheckSymbols::maybeVirtualMethod(const Name *name) const -{ - if (name) { - if (const Identifier *ident = name->identifier()) { - const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size()); - if (_potentialVirtualMethods.contains(id)) - return true; - } - } - - return false; -} - -static bool sortByLinePredicate(const CheckSymbols::Use &lhs, const CheckSymbols::Use &rhs) -{ - return lhs.line < rhs.line; -} - -void CheckSymbols::flush() -{ - _lineOfLastUsage = 0; - - if (_usages.isEmpty()) - return; - - qSort(_usages.begin(), _usages.end(), sortByLinePredicate); - reportResults(_usages); - _usages.clear(); - _usages.reserve(chunkSize); -} diff --git a/src/plugins/cppeditor/cppchecksymbols.h b/src/plugins/cppeditor/cppchecksymbols.h deleted file mode 100644 index 6bcf4933bd..0000000000 --- a/src/plugins/cppeditor/cppchecksymbols.h +++ /dev/null @@ -1,176 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** -** GNU Lesser General Public License Usage -** -** 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. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CPLUSPLUS_CHECKSYMBOLS_H -#define CPLUSPLUS_CHECKSYMBOLS_H - -#include "cppsemanticinfo.h" - -#include -#include -#include - -#include -#include -#include -#include - -namespace CPlusPlus { - -class CheckSymbols: - protected ASTVisitor, - public QRunnable, - public QFutureInterface -{ -public: - virtual ~CheckSymbols(); - - typedef CppEditor::Internal::SemanticInfo::Use Use; - typedef CppEditor::Internal::SemanticInfo::UseKind UseKind; - - virtual void run(); - - typedef QFuture Future; - - Future start() - { - this->setRunnable(this); - this->reportStarted(); - Future future = this->future(); - QThreadPool::globalInstance()->start(this, QThread::LowestPriority); - return future; - } - - static Future go(Document::Ptr doc, const LookupContext &context); - - static QMap > chunks(const QFuture &future, int from, int to) - { - QMap > chunks; - - for (int i = from; i < to; ++i) { - const Use use = future.resultAt(i); - if (! use.line) - continue; // skip it, it's an invalid use. - - const int blockNumber = use.line - 1; - chunks[blockNumber].append(use); - } - - return chunks; - } - -protected: - using ASTVisitor::visit; - using ASTVisitor::endVisit; - - CheckSymbols(Document::Ptr doc, const LookupContext &context); - - bool hasVirtualDestructor(Class *klass) const; - bool hasVirtualDestructor(ClassOrNamespace *binding) const; - - bool warning(unsigned line, unsigned column, const QString &text, unsigned length = 0); - bool warning(AST *ast, const QString &text); - - QByteArray textOf(AST *ast) const; - - bool maybeType(const Name *name) const; - bool maybeMember(const Name *name) const; - bool maybeStatic(const Name *name) const; - bool maybeVirtualMethod(const Name *name) const; - - void checkName(NameAST *ast, Scope *scope = 0); - void checkNamespace(NameAST *name); - - void addUse(const Use &use); - void addUse(unsigned tokenIndex, UseKind kind); - void addUse(NameAST *name, UseKind kind); - - void addType(ClassOrNamespace *b, NameAST *ast); - - void addTypeOrStatic(const QList &candidates, NameAST *ast); - void addStatic(const QList &candidates, NameAST *ast); - void addClassMember(const QList &candidates, NameAST *ast); - void addVirtualMethod(const QList &candidates, NameAST *ast, unsigned argumentCount); - - bool isTemplateClass(Symbol *s) const; - - Scope *enclosingScope() const; - FunctionDefinitionAST *enclosingFunctionDefinition(bool skipTopOfStack = false) const; - TemplateDeclarationAST *enclosingTemplateDeclaration() const; - - virtual bool preVisit(AST *); - virtual void postVisit(AST *); - - virtual bool visit(NamespaceAST *); - virtual bool visit(UsingDirectiveAST *); - virtual bool visit(SimpleDeclarationAST *); - virtual bool visit(NamedTypeSpecifierAST *); - virtual bool visit(ElaboratedTypeSpecifierAST *ast); - - virtual bool visit(EnumeratorAST *); - - virtual bool visit(SimpleNameAST *ast); - virtual bool visit(DestructorNameAST *ast); - virtual bool visit(QualifiedNameAST *ast); - virtual bool visit(TemplateIdAST *ast); - - virtual bool visit(TypenameTypeParameterAST *ast); - virtual bool visit(TemplateTypeParameterAST *ast); - - virtual bool visit(FunctionDefinitionAST *ast); - virtual bool visit(MemberAccessAST *ast); - virtual bool visit(CallAST *ast); - - virtual bool visit(MemInitializerAST *ast); - - NameAST *declaratorId(DeclaratorAST *ast) const; - - void flush(); - -private: - Document::Ptr _doc; - LookupContext _context; - TypeOfExpression typeOfExpression; - QString _fileName; - QList _diagnosticMessages; - QSet _potentialTypes; - QSet _potentialMembers; - QSet _potentialVirtualMethods; - QSet _potentialStatics; - QList _astStack; - QVector _usages; - unsigned _lineOfLastUsage; -}; - -} // namespace CPlusPlus - -#endif // CPLUSPLUS_CHECKSYMBOLS_H diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp index cd2a738887..9870716f0b 100644 --- a/src/plugins/cppeditor/cppeditor.cpp +++ b/src/plugins/cppeditor/cppeditor.cpp @@ -34,8 +34,6 @@ #include "cppeditorconstants.h" #include "cppplugin.h" #include "cpphighlighter.h" -#include "cppchecksymbols.h" -#include "cpplocalsymbols.h" #include "cppautocompleter.h" #include "cppquickfixassistant.h" @@ -63,8 +61,11 @@ #include #include +#include #include -#include +#include +#include +#include #include #include #include @@ -124,6 +125,7 @@ enum { }; using namespace CPlusPlus; +using namespace CppTools; using namespace CppEditor::Internal; namespace { @@ -424,7 +426,7 @@ CPPEditorWidget::CPPEditorWidget(QWidget *parent) , m_commentsSettings(CppTools::CppToolsSettings::instance()->commentsSettings()) { m_initialized = false; - qRegisterMetaType("CppEditor::Internal::SemanticInfo"); + qRegisterMetaType("CppTools::SemanticInfo"); m_semanticHighlighter = new SemanticHighlighter(this); m_semanticHighlighter->start(); @@ -552,8 +554,8 @@ void CPPEditorWidget::createToolBar(CPPEditor *editor) connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateUses())); connect(this, SIGNAL(textChanged()), this, SLOT(updateUses())); - connect(m_semanticHighlighter, SIGNAL(changed(CppEditor::Internal::SemanticInfo)), - this, SLOT(updateSemanticInfo(CppEditor::Internal::SemanticInfo))); + connect(m_semanticHighlighter, SIGNAL(changed(CppTools::SemanticInfo)), + this, SLOT(updateSemanticInfo(CppTools::SemanticInfo))); editor->insertExtraToolBarWidget(TextEditor::BaseTextEditor::Left, m_outlineCombo); } @@ -1849,11 +1851,11 @@ void CPPEditorWidget::updateSemanticInfo(const SemanticInfo &semanticInfo) if (! semanticHighlighterDisabled && semanticInfo.doc) { if (Core::EditorManager::instance()->currentEditor() == editor()) { - LookupContext context(semanticInfo.doc, semanticInfo.snapshot); - CheckSymbols::Future f = CheckSymbols::go(semanticInfo.doc, context); - m_highlighter = f; - m_highlightRevision = semanticInfo.revision; - m_highlightWatcher.setFuture(m_highlighter); + if (CppTools::CppHighlightingSupport *hs = modelManager()->highlightingSupport(editor())) { + m_highlighter = hs->highlightingFuture(semanticInfo.doc, semanticInfo.snapshot); + m_highlightRevision = semanticInfo.revision; + m_highlightWatcher.setFuture(m_highlighter); + } } } @@ -2154,21 +2156,9 @@ TextEditor::IAssistInterface *CPPEditorWidget::createAssistInterface( TextEditor::AssistReason reason) const { if (kind == TextEditor::Completion) { - QStringList includePaths; - QStringList frameworkPaths; - if (ProjectExplorer::Project *project = - ProjectExplorer::ProjectExplorerPlugin::currentProject()) { - includePaths = m_modelManager->projectInfo(project).includePaths; - frameworkPaths = m_modelManager->projectInfo(project).frameworkPaths; - } - return new CppTools::Internal::CppCompletionAssistInterface( - document(), - position(), - editor()->file(), - reason, - m_modelManager->snapshot(), - includePaths, - frameworkPaths); + if (CppTools::CppCompletionSupport *cs = m_modelManager->completionSupport(editor())) + return cs->createAssistInterface(ProjectExplorer::ProjectExplorerPlugin::currentProject(), + document(), position(), reason); } else if (kind == TextEditor::QuickFix) { if (!semanticInfo().doc || isOutdated()) return 0; diff --git a/src/plugins/cppeditor/cppeditor.h b/src/plugins/cppeditor/cppeditor.h index 546d5ae191..2f9b235e92 100644 --- a/src/plugins/cppeditor/cppeditor.h +++ b/src/plugins/cppeditor/cppeditor.h @@ -34,7 +34,6 @@ #define CPPEDITOR_H #include "cppeditorenums.h" -#include "cppsemanticinfo.h" #include "cppfunctiondecldeflink.h" #include @@ -43,6 +42,7 @@ #include #include #include +#include #include #include @@ -124,12 +124,12 @@ public: } }; - SemanticInfo semanticInfo(const Source &source); + CppTools::SemanticInfo semanticInfo(const Source &source); void rehighlight(const Source &source); Q_SIGNALS: - void changed(const CppEditor::Internal::SemanticInfo &semanticInfo); + void changed(const CppTools::SemanticInfo &semanticInfo); protected: virtual void run(); @@ -142,7 +142,7 @@ private: QWaitCondition m_condition; bool m_done; Source m_source; - SemanticInfo m_lastSemanticInfo; + CppTools::SemanticInfo m_lastSemanticInfo; }; class CPPEditor : public TextEditor::BaseTextEditor @@ -172,7 +172,7 @@ public: unsigned editorRevision() const; bool isOutdated() const; - SemanticInfo semanticInfo() const; + CppTools::SemanticInfo semanticInfo() const; CPlusPlus::OverviewModel *outlineModel() const; QModelIndex outlineModelIndex(); @@ -242,7 +242,7 @@ private Q_SLOTS: void onDocumentUpdated(CPlusPlus::Document::Ptr doc); void onContentsChanged(int position, int charsRemoved, int charsAdded); - void updateSemanticInfo(const CppEditor::Internal::SemanticInfo &semanticInfo); + void updateSemanticInfo(const CppTools::SemanticInfo &semanticInfo); void highlightSymbolUsages(int from, int to); void finishHighlightSymbolUsages(); @@ -255,7 +255,7 @@ private Q_SLOTS: void onCommentsSettingsChanged(const CppTools::CommentsSettings &settings); private: - void markSymbols(const QTextCursor &tc, const SemanticInfo &info); + void markSymbols(const QTextCursor &tc, const CppTools::SemanticInfo &info); bool sortedOutline() const; CPlusPlus::Symbol *findDefinition(CPlusPlus::Symbol *symbol, const CPlusPlus::Snapshot &snapshot) const; @@ -264,8 +264,8 @@ private: SemanticHighlighter::Source currentSource(bool force = false); - void highlightUses(const QList &uses, - const SemanticInfo &semanticInfo, + void highlightUses(const QList &uses, + const CppTools::SemanticInfo &semanticInfo, QList *selections); void createToolBar(CPPEditor *editable); @@ -315,13 +315,13 @@ private: QTextCursor m_currentRenameSelectionEnd; SemanticHighlighter *m_semanticHighlighter; - SemanticInfo m_lastSemanticInfo; + CppTools::SemanticInfo m_lastSemanticInfo; QList m_quickFixes; bool m_objcEnabled; bool m_initialized; - QFuture m_highlighter; - QFutureWatcher m_highlightWatcher; + QFuture m_highlighter; + QFutureWatcher m_highlightWatcher; unsigned m_highlightRevision; // the editor revision that requested the highlight QFuture > m_references; diff --git a/src/plugins/cppeditor/cppeditor.pro b/src/plugins/cppeditor/cppeditor.pro index d90fc0a052..1178b5f70b 100644 --- a/src/plugins/cppeditor/cppeditor.pro +++ b/src/plugins/cppeditor/cppeditor.pro @@ -14,11 +14,8 @@ HEADERS += cppplugin.h \ cppeditorenums.h \ cppeditor_global.h \ cppclasswizard.h \ - cppchecksymbols.h \ - cppsemanticinfo.h \ cppoutline.h \ cppinsertdecldef.h \ - cpplocalsymbols.h \ cpptypehierarchy.h \ cppelementevaluator.h \ cppautocompleter.h \ @@ -36,11 +33,8 @@ SOURCES += cppplugin.cpp \ cppfilewizard.cpp \ cppclasswizard.cpp \ cppquickfixes.cpp \ - cppchecksymbols.cpp \ - cppsemanticinfo.cpp \ cppoutline.cpp \ cppinsertdecldef.cpp \ - cpplocalsymbols.cpp \ cpptypehierarchy.cpp \ cppelementevaluator.cpp \ cppautocompleter.cpp \ diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp index a39ba82bd0..3c79791d36 100644 --- a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp +++ b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp @@ -34,7 +34,6 @@ #include "cppeditor.h" #include "cppquickfixassistant.h" -#include "cpplocalsymbols.h" #include #include @@ -44,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -61,6 +61,7 @@ using namespace CPlusPlus; using namespace CppEditor; using namespace CppEditor::Internal; +using namespace CppTools; FunctionDeclDefLinkFinder::FunctionDeclDefLinkFinder(QObject *parent) : QObject(parent) diff --git a/src/plugins/cppeditor/cpplocalsymbols.cpp b/src/plugins/cppeditor/cpplocalsymbols.cpp deleted file mode 100644 index b688064433..0000000000 --- a/src/plugins/cppeditor/cpplocalsymbols.cpp +++ /dev/null @@ -1,302 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** -** GNU Lesser General Public License Usage -** -** 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. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cpplocalsymbols.h" -#include "cppsemanticinfo.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace CPlusPlus; -using namespace CppEditor::Internal; - -namespace { - -class FindLocalSymbols: protected ASTVisitor -{ - Scope *_functionScope; - Document::Ptr _doc; - -public: - FindLocalSymbols(Document::Ptr doc) - : ASTVisitor(doc->translationUnit()), _doc(doc), hasD(false), hasQ(false) - { } - - // local and external uses. - SemanticInfo::LocalUseMap localUses; - bool hasD; - bool hasQ; - - void operator()(DeclarationAST *ast) - { - localUses.clear(); - - if (!ast) - return; - - if (FunctionDefinitionAST *def = ast->asFunctionDefinition()) { - if (def->symbol) { - _functionScope = def->symbol; - accept(ast); - } - } else if (ObjCMethodDeclarationAST *decl = ast->asObjCMethodDeclaration()) { - if (decl->method_prototype->symbol) { - _functionScope = decl->method_prototype->symbol; - accept(ast); - } - } - } - -protected: - using ASTVisitor::visit; - using ASTVisitor::endVisit; - - void enterScope(Scope *scope) - { - _scopeStack.append(scope); - - for (unsigned i = 0; i < scope->memberCount(); ++i) { - if (Symbol *member = scope->memberAt(i)) { - if (member->isTypedef()) - continue; - else if (! member->isGenerated() && (member->isDeclaration() || member->isArgument())) { - if (member->name() && member->name()->isNameId()) { - const Identifier *id = member->identifier(); - unsigned line, column; - getTokenStartPosition(member->sourceLocation(), &line, &column); - localUses[member].append(SemanticInfo::Use(line, column, id->size(), SemanticInfo::LocalUse)); - } - } - } - } - } - - bool checkLocalUse(NameAST *nameAst, unsigned firstToken) - { - if (SimpleNameAST *simpleName = nameAst->asSimpleName()) { - const Identifier *id = identifier(simpleName->identifier_token); - for (int i = _scopeStack.size() - 1; i != -1; --i) { - if (Symbol *member = _scopeStack.at(i)->find(id)) { - if (member->isTypedef() || - !(member->isDeclaration() || member->isArgument())) - continue; - else if (!member->isGenerated() && (member->sourceLocation() < firstToken || member->enclosingScope()->isFunction())) { - unsigned line, column; - getTokenStartPosition(simpleName->identifier_token, &line, &column); - localUses[member].append(SemanticInfo::Use(line, column, id->size(), SemanticInfo::LocalUse)); - return false; - } - } - } - } - - return true; - } - - virtual bool visit(IdExpressionAST *ast) - { - return checkLocalUse(ast->name, ast->firstToken()); - } - - virtual bool visit(SizeofExpressionAST *ast) - { - if (ast->expression && ast->expression->asTypeId()) { - TypeIdAST *typeId = ast->expression->asTypeId(); - if (!typeId->declarator && typeId->type_specifier_list && !typeId->type_specifier_list->next) { - if (NamedTypeSpecifierAST *namedTypeSpec = typeId->type_specifier_list->value->asNamedTypeSpecifier()) { - if (checkLocalUse(namedTypeSpec->name, namedTypeSpec->firstToken())) - return false; - } - } - } - - return true; - } - - virtual bool visit(CastExpressionAST *ast) - { - if (ast->expression && ast->expression->asUnaryExpression()) { - TypeIdAST *typeId = ast->type_id->asTypeId(); - if (typeId && !typeId->declarator && typeId->type_specifier_list && !typeId->type_specifier_list->next) { - if (NamedTypeSpecifierAST *namedTypeSpec = typeId->type_specifier_list->value->asNamedTypeSpecifier()) { - if (checkLocalUse(namedTypeSpec->name, namedTypeSpec->firstToken())) { - accept(ast->expression); - return false; - } - } - } - } - - return true; - } - - virtual bool visit(QtMemberDeclarationAST *ast) - { - if (tokenKind(ast->q_token) == T_Q_D) - hasD = true; - else - hasQ = true; - - return true; - } - - virtual bool visit(FunctionDefinitionAST *ast) - { - if (ast->symbol) - enterScope(ast->symbol); - return true; - } - - virtual void endVisit(FunctionDefinitionAST *ast) - { - if (ast->symbol) - _scopeStack.removeLast(); - } - - virtual bool visit(CompoundStatementAST *ast) - { - if (ast->symbol) - enterScope(ast->symbol); - return true; - } - - virtual void endVisit(CompoundStatementAST *ast) - { - if (ast->symbol) - _scopeStack.removeLast(); - } - - virtual bool visit(IfStatementAST *ast) - { - if (ast->symbol) - enterScope(ast->symbol); - return true; - } - - virtual void endVisit(IfStatementAST *ast) - { - if (ast->symbol) - _scopeStack.removeLast(); - } - - virtual bool visit(WhileStatementAST *ast) - { - if (ast->symbol) - enterScope(ast->symbol); - return true; - } - - virtual void endVisit(WhileStatementAST *ast) - { - if (ast->symbol) - _scopeStack.removeLast(); - } - - virtual bool visit(ForStatementAST *ast) - { - if (ast->symbol) - enterScope(ast->symbol); - return true; - } - - virtual void endVisit(ForStatementAST *ast) - { - if (ast->symbol) - _scopeStack.removeLast(); - } - - virtual bool visit(ForeachStatementAST *ast) - { - if (ast->symbol) - enterScope(ast->symbol); - return true; - } - - virtual void endVisit(ForeachStatementAST *ast) - { - if (ast->symbol) - _scopeStack.removeLast(); - } - - virtual bool visit(SwitchStatementAST *ast) - { - if (ast->symbol) - enterScope(ast->symbol); - return true; - } - - virtual void endVisit(SwitchStatementAST *ast) - { - if (ast->symbol) - _scopeStack.removeLast(); - } - - virtual bool visit(CatchClauseAST *ast) - { - if (ast->symbol) - enterScope(ast->symbol); - return true; - } - - virtual void endVisit(CatchClauseAST *ast) - { - if (ast->symbol) - _scopeStack.removeLast(); - } - - virtual bool visit(ExpressionOrDeclarationStatementAST *ast) - { - accept(ast->declaration); - return false; - } - -private: - QList _scopeStack; -}; - -} // end of anonymous namespace - - -LocalSymbols::LocalSymbols(CPlusPlus::Document::Ptr doc, CPlusPlus::DeclarationAST *ast) -{ - FindLocalSymbols findLocalSymbols(doc); - findLocalSymbols(ast); - hasD = findLocalSymbols.hasD; - hasQ = findLocalSymbols.hasQ; - uses = findLocalSymbols.localUses; -} diff --git a/src/plugins/cppeditor/cpplocalsymbols.h b/src/plugins/cppeditor/cpplocalsymbols.h deleted file mode 100644 index 670fcaaa24..0000000000 --- a/src/plugins/cppeditor/cpplocalsymbols.h +++ /dev/null @@ -1,58 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** -** GNU Lesser General Public License Usage -** -** 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. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CPPLOCALSYMBOLS_H -#define CPPLOCALSYMBOLS_H - -#include "cppsemanticinfo.h" -#include -#include - -namespace CppEditor { -namespace Internal { - -class LocalSymbols -{ - Q_DISABLE_COPY(LocalSymbols) - -public: - LocalSymbols(CPlusPlus::Document::Ptr doc, CPlusPlus::DeclarationAST *ast); - - bool hasD; - bool hasQ; - SemanticInfo::LocalUseMap uses; -}; - -} // namespace Internal -} // namespace CppEditor - -#endif // CPPLOCALSYMBOLS_H diff --git a/src/plugins/cppeditor/cppquickfixassistant.h b/src/plugins/cppeditor/cppquickfixassistant.h index 03bafe8b27..ca5bdd810f 100644 --- a/src/plugins/cppeditor/cppquickfixassistant.h +++ b/src/plugins/cppeditor/cppquickfixassistant.h @@ -33,7 +33,7 @@ #ifndef CPPQUICKFIXASSISTANT_H #define CPPQUICKFIXASSISTANT_H -#include "cppsemanticinfo.h" +#include #include #include @@ -59,7 +59,7 @@ public: const QList &path() const; CPlusPlus::Snapshot snapshot() const; - CppEditor::Internal::SemanticInfo semanticInfo() const; + CppTools::SemanticInfo semanticInfo() const; const CPlusPlus::LookupContext &context() const; CPPEditorWidget *editor() const; @@ -70,7 +70,7 @@ public: private: CPPEditorWidget *m_editor; - CppEditor::Internal::SemanticInfo m_semanticInfo; + CppTools::SemanticInfo m_semanticInfo; CPlusPlus::Snapshot m_snapshot; CppTools::CppRefactoringFilePtr m_currentFile; CPlusPlus::LookupContext m_context; diff --git a/src/plugins/cppeditor/cppsemanticinfo.cpp b/src/plugins/cppeditor/cppsemanticinfo.cpp deleted file mode 100644 index 14231028a9..0000000000 --- a/src/plugins/cppeditor/cppsemanticinfo.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** -** GNU Lesser General Public License Usage -** -** 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. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#include "cppsemanticinfo.h" - -using namespace CppEditor::Internal; - -SemanticInfo::SemanticInfo() - : revision(0), hasQ(false), hasD(false), forced(false) -{ -} diff --git a/src/plugins/cppeditor/cppsemanticinfo.h b/src/plugins/cppeditor/cppsemanticinfo.h deleted file mode 100644 index d177d4c5a6..0000000000 --- a/src/plugins/cppeditor/cppsemanticinfo.h +++ /dev/null @@ -1,76 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** -** GNU Lesser General Public License Usage -** -** 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. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -**************************************************************************/ - -#ifndef CPPSEMANTICINFO_H -#define CPPSEMANTICINFO_H - -#include -#include -#include -#include - -namespace CppEditor { -namespace Internal { - -class CPPEditorWidget; - -class SemanticInfo -{ -public: - typedef TextEditor::SemanticHighlighter::Result Use; - enum UseKind { - TypeUse = 0, - LocalUse, - FieldUse, - StaticUse, - VirtualMethodUse - }; - - typedef QHash > LocalUseMap; - typedef QHashIterator > LocalUseIterator; - - SemanticInfo(); - - unsigned revision; - bool hasQ: 1; - bool hasD: 1; - bool forced: 1; - CPlusPlus::Snapshot snapshot; - CPlusPlus::Document::Ptr doc; - LocalUseMap localUses; - QList objcKeywords; -}; - -} // namespace Internal -} // namespace CppEditor; - -#endif // CPPSEMANTICINFO_H diff --git a/src/plugins/cpptools/cppchecksymbols.cpp b/src/plugins/cpptools/cppchecksymbols.cpp new file mode 100644 index 0000000000..d1bdb3c281 --- /dev/null +++ b/src/plugins/cpptools/cppchecksymbols.cpp @@ -0,0 +1,1110 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "cppchecksymbols.h" +#include "cpplocalsymbols.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +using namespace CPlusPlus; +using namespace CppTools; + +namespace { + +class FriendlyThread: public QThread +{ +public: + using QThread::msleep; +}; + +class CollectSymbols: protected SymbolVisitor +{ + Document::Ptr _doc; + Snapshot _snapshot; + QSet _types; + QSet _members; + QSet _virtualMethods; + QSet _statics; + bool _mainDocument; + +public: + CollectSymbols(Document::Ptr doc, const Snapshot &snapshot) + : _doc(doc), _snapshot(snapshot), _mainDocument(false) + { + QSet processed; + process(doc, &processed); + } + + const QSet &types() const + { + return _types; + } + + const QSet &members() const + { + return _members; + } + + const QSet &virtualMethods() const + { + return _virtualMethods; + } + + const QSet &statics() const + { + return _statics; + } + +protected: + void process(Document::Ptr doc, QSet *processed) + { + if (! doc) + return; + else if (! processed->contains(doc->globalNamespace())) { + processed->insert(doc->globalNamespace()); + + foreach (const Document::Include &i, doc->includes()) + process(_snapshot.document(i.fileName()), processed); + + _mainDocument = (doc == _doc); // ### improve + accept(doc->globalNamespace()); + } + } + + void addType(const Identifier *id) + { + if (id) + _types.insert(QByteArray::fromRawData(id->chars(), id->size())); + } + + void addType(const Name *name) + { + if (! name) { + return; + + } else if (const QualifiedNameId *q = name->asQualifiedNameId()) { + addType(q->base()); + addType(q->name()); + + } else if (name->isNameId() || name->isTemplateNameId()) { + addType(name->identifier()); + + } + } + + void addMember(const Name *name) + { + if (! name) { + return; + + } else if (name->isNameId()) { + const Identifier *id = name->identifier(); + _members.insert(QByteArray::fromRawData(id->chars(), id->size())); + + } + } + + 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 addStatic(const Name *name) + { + if (! name) { + return; + + } else if (name->isNameId() || name->isTemplateNameId()) { + const Identifier *id = name->identifier(); + _statics.insert(QByteArray::fromRawData(id->chars(), id->size())); + + } + } + + // nothing to do + virtual bool visit(UsingNamespaceDirective *) { return true; } + virtual bool visit(UsingDeclaration *) { return true; } + virtual bool visit(Argument *) { return true; } + virtual bool visit(BaseClass *) { return true; } + + virtual bool visit(Function *symbol) + { + if (symbol->isVirtual()) + addVirtualMethod(symbol->name()); + + return true; + } + + virtual bool visit(Block *) + { + return true; + } + + virtual bool visit(NamespaceAlias *symbol) + { + addType(symbol->name()); + return true; + } + + virtual bool visit(Declaration *symbol) + { + if (symbol->enclosingEnum() != 0) + addStatic(symbol->name()); + + if (Function *funTy = symbol->type()->asFunctionType()) { + if (funTy->isVirtual()) + addVirtualMethod(symbol->name()); + } + + if (symbol->isTypedef()) + addType(symbol->name()); + else if (! symbol->type()->isFunctionType() && symbol->enclosingScope()->isClass()) + addMember(symbol->name()); + + return true; + } + + virtual bool visit(TypenameArgument *symbol) + { + addType(symbol->name()); + return true; + } + + virtual bool visit(Enum *symbol) + { + addType(symbol->name()); + return true; + } + + virtual bool visit(Namespace *symbol) + { + addType(symbol->name()); + return true; + } + + virtual bool visit(Template *) + { + return true; + } + + virtual bool visit(Class *symbol) + { + addType(symbol->name()); + return true; + } + + virtual bool visit(ForwardClassDeclaration *symbol) + { + addType(symbol->name()); + return true; + } + + // Objective-C + virtual bool visit(ObjCBaseClass *) { return true; } + virtual bool visit(ObjCBaseProtocol *) { return true; } + virtual bool visit(ObjCPropertyDeclaration *) { return true; } + virtual bool visit(ObjCMethod *) { return true; } + + virtual bool visit(ObjCClass *symbol) + { + addType(symbol->name()); + return true; + } + + virtual bool visit(ObjCForwardClassDeclaration *symbol) + { + addType(symbol->name()); + return true; + } + + virtual bool visit(ObjCProtocol *symbol) + { + addType(symbol->name()); + return true; + } + + virtual bool visit(ObjCForwardProtocolDeclaration *symbol) + { + addType(symbol->name()); + return true; + } +}; + +} // end of anonymous namespace + +CheckSymbols::Future CheckSymbols::go(Document::Ptr doc, const LookupContext &context) +{ + QTC_ASSERT(doc, return Future()); + + return (new CheckSymbols(doc, context))->start(); +} + +CheckSymbols::CheckSymbols(Document::Ptr doc, const LookupContext &context) + : ASTVisitor(doc->translationUnit()), _doc(doc), _context(context) + , _lineOfLastUsage(0) +{ + CollectSymbols collectTypes(doc, context.snapshot()); + + _fileName = doc->fileName(); + _potentialTypes = collectTypes.types(); + _potentialMembers = collectTypes.members(); + _potentialVirtualMethods = collectTypes.virtualMethods(); + _potentialStatics = collectTypes.statics(); + + typeOfExpression.init(_doc, _context.snapshot(), _context.bindings()); +} + +CheckSymbols::~CheckSymbols() +{ } + +void CheckSymbols::run() +{ + _diagnosticMessages.clear(); + + if (! isCanceled()) { + if (_doc->translationUnit()) { + accept(_doc->translationUnit()->ast()); + flush(); + } + } + + reportFinished(); +} + +bool CheckSymbols::warning(unsigned line, unsigned column, const QString &text, unsigned length) +{ + Document::DiagnosticMessage m(Document::DiagnosticMessage::Warning, _fileName, line, column, text, length); + _diagnosticMessages.append(m); + return false; +} + +bool CheckSymbols::warning(AST *ast, const QString &text) +{ + const Token &firstToken = tokenAt(ast->firstToken()); + const Token &lastToken = tokenAt(ast->lastToken() - 1); + + const unsigned length = lastToken.end() - firstToken.begin(); + unsigned line = 1, column = 1; + getTokenStartPosition(ast->firstToken(), &line, &column); + + warning(line, column, text, length); + return false; +} + +FunctionDefinitionAST *CheckSymbols::enclosingFunctionDefinition(bool skipTopOfStack) const +{ + int index = _astStack.size() - 1; + if (skipTopOfStack && !_astStack.isEmpty()) + --index; + for (; index != -1; --index) { + AST *ast = _astStack.at(index); + + if (FunctionDefinitionAST *funDef = ast->asFunctionDefinition()) + return funDef; + } + + return 0; +} + +TemplateDeclarationAST *CheckSymbols::enclosingTemplateDeclaration() const +{ + for (int index = _astStack.size() - 1; index != -1; --index) { + AST *ast = _astStack.at(index); + + if (TemplateDeclarationAST *funDef = ast->asTemplateDeclaration()) + return funDef; + } + + return 0; +} + +Scope *CheckSymbols::enclosingScope() const +{ + for (int index = _astStack.size() - 1; index != -1; --index) { + AST *ast = _astStack.at(index); + + if (NamespaceAST *ns = ast->asNamespace()) { + if (ns->symbol) + return ns->symbol; + + } else if (ClassSpecifierAST *classSpec = ast->asClassSpecifier()) { + if (classSpec->symbol) + return classSpec->symbol; + + } else if (FunctionDefinitionAST *funDef = ast->asFunctionDefinition()) { + if (funDef->symbol) + return funDef->symbol; + + } else if (CompoundStatementAST *blockStmt = ast->asCompoundStatement()) { + if (blockStmt->symbol) + return blockStmt->symbol; + + } else if (IfStatementAST *ifStmt = ast->asIfStatement()) { + if (ifStmt->symbol) + return ifStmt->symbol; + + } else if (WhileStatementAST *whileStmt = ast->asWhileStatement()) { + if (whileStmt->symbol) + return whileStmt->symbol; + + } else if (ForStatementAST *forStmt = ast->asForStatement()) { + if (forStmt->symbol) + return forStmt->symbol; + + } else if (ForeachStatementAST *foreachStmt = ast->asForeachStatement()) { + if (foreachStmt->symbol) + return foreachStmt->symbol; + + } else if (SwitchStatementAST *switchStmt = ast->asSwitchStatement()) { + if (switchStmt->symbol) + return switchStmt->symbol; + + } else if (CatchClauseAST *catchClause = ast->asCatchClause()) { + if (catchClause->symbol) + return catchClause->symbol; + + } + } + + return _doc->globalNamespace(); +} + +bool CheckSymbols::preVisit(AST *ast) +{ + _astStack.append(ast); + + if (isCanceled()) + return false; + + return true; +} + +void CheckSymbols::postVisit(AST *) +{ + _astStack.takeLast(); +} + +bool CheckSymbols::visit(NamespaceAST *ast) +{ + if (ast->identifier_token) { + const Token &tok = tokenAt(ast->identifier_token); + if (! tok.generated()) { + unsigned line, column; + getTokenStartPosition(ast->identifier_token, &line, &column); + Use use(line, column, tok.length(), SemanticInfo::TypeUse); + addUse(use); + } + } + + return true; +} + +bool CheckSymbols::visit(UsingDirectiveAST *) +{ + return true; +} + +bool CheckSymbols::visit(EnumeratorAST *ast) +{ + addUse(ast->identifier_token, SemanticInfo::StaticUse); + return true; +} + +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()) { + addUse(declId, SemanticInfo::VirtualMethodUse); + } else if (maybeVirtualMethod(decl->name())) { + addVirtualMethod(_context.lookup(decl->name(), decl->enclosingScope()), declId, funTy->argumentCount()); + } + } + } + } + } + + return true; +} + +bool CheckSymbols::visit(NamedTypeSpecifierAST *) +{ + return true; +} + +bool CheckSymbols::visit(ElaboratedTypeSpecifierAST *ast) +{ + accept(ast->attribute_list); + accept(ast->name); + addUse(ast->name, SemanticInfo::TypeUse); + return false; +} + +bool CheckSymbols::visit(MemberAccessAST *ast) +{ + accept(ast->base_expression); + if (! ast->member_name) + return false; + + if (const Name *name = ast->member_name->name) { + if (const Identifier *ident = name->identifier()) { + const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size()); + if (_potentialMembers.contains(id)) { + const Token start = tokenAt(ast->firstToken()); + const Token end = tokenAt(ast->lastToken() - 1); + const QByteArray expression = _doc->utf8Source().mid(start.begin(), end.end() - start.begin()); + + const QList candidates = + typeOfExpression(expression, enclosingScope(), TypeOfExpression::Preprocess); + addClassMember(candidates, ast->member_name); + } + } + } + + 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)) { + const QByteArray expression = textOf(access); + + const QList candidates = + typeOfExpression(expression, enclosingScope(), + TypeOfExpression::Preprocess); + + NameAST *memberName = access->member_name; + if (QualifiedNameAST *q = memberName->asQualifiedName()) + memberName = q->unqualified_name; + + addVirtualMethod(candidates, memberName, argumentCount); + } + } + } else if (IdExpressionAST *idExpr = ast->base_expression->asIdExpression()) { + if (const Name *name = idExpr->name->name) { + if (maybeVirtualMethod(name)) { + NameAST *exprName = idExpr->name; + if (QualifiedNameAST *q = exprName->asQualifiedName()) + exprName = q->unqualified_name; + + const QList candidates = + typeOfExpression(textOf(idExpr), enclosingScope(), + TypeOfExpression::Preprocess); + addVirtualMethod(candidates, exprName, 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->utf8Source().mid(start.begin(), end.end() - start.begin()); + return text; +} + +void CheckSymbols::checkNamespace(NameAST *name) +{ + if (! name) + return; + + unsigned line, column; + getTokenStartPosition(name->firstToken(), &line, &column); + + if (ClassOrNamespace *b = _context.lookupType(name->name, enclosingScope())) { + foreach (Symbol *s, b->symbols()) { + if (s->isNamespace()) + return; + } + } + + const unsigned length = tokenAt(name->lastToken() - 1).end() - tokenAt(name->firstToken()).begin(); + warning(line, column, QCoreApplication::translate("CheckUndefinedSymbols", "Expected a namespace-name"), length); +} + +bool CheckSymbols::hasVirtualDestructor(Class *klass) const +{ + if (! klass) + return false; + const Identifier *id = klass->identifier(); + if (! id) + return false; + for (Symbol *s = klass->find(id); s; s = s->next()) { + if (! s->name()) + continue; + else if (s->name()->isDestructorNameId()) { + if (Function *funTy = s->type()->asFunctionType()) { + if (funTy->isVirtual() && id->isEqualTo(s->identifier())) + return true; + } + } + } + return false; +} + +bool CheckSymbols::hasVirtualDestructor(ClassOrNamespace *binding) const +{ + QSet processed; + QList todo; + todo.append(binding); + + while (! todo.isEmpty()) { + ClassOrNamespace *b = todo.takeFirst(); + if (b && ! processed.contains(b)) { + processed.insert(b); + foreach (Symbol *s, b->symbols()) { + if (Class *k = s->asClass()) { + if (hasVirtualDestructor(k)) + return true; + } + } + + todo += b->usings(); + } + } + + return false; +} + +void CheckSymbols::checkName(NameAST *ast, Scope *scope) +{ + if (ast && ast->name) { + if (! scope) + scope = enclosingScope(); + + if (ast->asDestructorName() != 0) { + Class *klass = scope->asClass(); + if (hasVirtualDestructor(_context.lookupType(klass))) + addUse(ast, SemanticInfo::VirtualMethodUse); + } else if (maybeType(ast->name) || maybeStatic(ast->name)) { + const QList candidates = _context.lookup(ast->name, scope); + addTypeOrStatic(candidates, ast); + } else if (maybeMember(ast->name)) { + const QList candidates = _context.lookup(ast->name, scope); + addClassMember(candidates, ast); + } + } +} + +bool CheckSymbols::visit(SimpleNameAST *ast) +{ + checkName(ast); + return true; +} + +bool CheckSymbols::visit(TemplateIdAST *ast) +{ + checkName(ast); + return true; +} + +bool CheckSymbols::visit(DestructorNameAST *ast) +{ + checkName(ast); + return true; +} + +bool CheckSymbols::visit(QualifiedNameAST *ast) +{ + if (ast->name) { + ClassOrNamespace *binding = 0; + if (NestedNameSpecifierListAST *it = ast->nested_name_specifier_list) { + NestedNameSpecifierAST *nested_name_specifier = it->value; + if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) { // ### remove shadowing + + if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId()) + accept(template_id->template_argument_list); + + const Name *name = class_or_namespace_name->name; + binding = _context.lookupType(name, enclosingScope()); + addType(binding, class_or_namespace_name); + + for (it = it->next; it; it = it->next) { + NestedNameSpecifierAST *nested_name_specifier = it->value; + + if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) { + if (TemplateIdAST *template_id = class_or_namespace_name->asTemplateId()) { + if (template_id->template_token) { + addUse(template_id, SemanticInfo::TypeUse); + binding = 0; // there's no way we can find a binding. + } + + accept(template_id->template_argument_list); + if (! binding) + continue; + } + + if (binding) { + binding = binding->findType(class_or_namespace_name->name); + addType(binding, class_or_namespace_name); + } + } + } + } + } + + if (binding && ast->unqualified_name) { + if (ast->unqualified_name->asDestructorName() != 0) { + if (hasVirtualDestructor(binding)) + addUse(ast->unqualified_name, SemanticInfo::VirtualMethodUse); + } else { + addTypeOrStatic(binding->find(ast->unqualified_name->name), ast->unqualified_name); + } + + if (TemplateIdAST *template_id = ast->unqualified_name->asTemplateId()) + accept(template_id->template_argument_list); + } + } + + return false; +} + +bool CheckSymbols::visit(TypenameTypeParameterAST *ast) +{ + addUse(ast->name, SemanticInfo::TypeUse); + accept(ast->type_id); + return false; +} + +bool CheckSymbols::visit(TemplateTypeParameterAST *ast) +{ + accept(ast->template_parameter_list); + addUse(ast->name, SemanticInfo::TypeUse); + accept(ast->type_id); + return false; +} + +bool CheckSymbols::visit(MemInitializerAST *ast) +{ + if (FunctionDefinitionAST *enclosingFunction = enclosingFunctionDefinition()) { + if (ast->name && enclosingFunction->symbol) { + if (ClassOrNamespace *binding = _context.lookupType(enclosingFunction->symbol)) { + foreach (Symbol *s, binding->symbols()) { + if (Class *klass = s->asClass()){ + checkName(ast->name, klass); + break; + } + } + } + } + + accept(ast->expression_list); + } + + return false; +} + +bool CheckSymbols::visit(FunctionDefinitionAST *ast) +{ + AST *thisFunction = _astStack.takeLast(); + accept(ast->decl_specifier_list); + _astStack.append(thisFunction); + + if (ast->declarator && ast->symbol && ! 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()) { + addUse(declId, SemanticInfo::VirtualMethodUse); + } else if (maybeVirtualMethod(fun->name())) { + addVirtualMethod(_context.lookup(fun->name(), fun->enclosingScope()), declId, fun->argumentCount()); + } + } + } + + accept(ast->declarator); + accept(ast->ctor_initializer); + accept(ast->function_body); + + const LocalSymbols locals(_doc, ast); + foreach (const QList &uses, locals.uses) { + foreach (const SemanticInfo::Use &u, uses) + addUse(u); + } + + if (!enclosingFunctionDefinition(true)) + flush(); + + return false; +} + +void CheckSymbols::addUse(NameAST *ast, UseKind kind) +{ + if (! ast) + return; + + if (QualifiedNameAST *q = ast->asQualifiedName()) + ast = q->unqualified_name; + + if (! ast) + return; // nothing to do + else if (ast->asOperatorFunctionId() != 0 || ast->asConversionFunctionId() != 0) + return; // nothing to do + + unsigned startToken = ast->firstToken(); + + if (DestructorNameAST *dtor = ast->asDestructorName()) + startToken = dtor->identifier_token; + + else if (TemplateIdAST *templ = ast->asTemplateId()) + startToken = templ->identifier_token; + + addUse(startToken, kind); +} + +void CheckSymbols::addUse(unsigned tokenIndex, UseKind kind) +{ + if (! tokenIndex) + return; + + const Token &tok = tokenAt(tokenIndex); + if (tok.generated()) + return; + + unsigned line, column; + getTokenStartPosition(tokenIndex, &line, &column); + const unsigned length = tok.length(); + + const Use use(line, column, length, kind); + addUse(use); +} + +static const int chunkSize = 50; + +void CheckSymbols::addUse(const Use &use) +{ + if (!use.line) + return; + + if (! enclosingFunctionDefinition()) { + if (_usages.size() >= chunkSize) { + if (use.line > _lineOfLastUsage) + flush(); + } + } + + _lineOfLastUsage = qMax(_lineOfLastUsage, use.line); + _usages.append(use); +} + +void CheckSymbols::addType(ClassOrNamespace *b, NameAST *ast) +{ + if (! b) + 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, SemanticInfo::TypeUse); + addUse(use); + //qDebug() << "added use" << oo(ast->name) << line << column << length; +} + +bool CheckSymbols::isTemplateClass(Symbol *symbol) const +{ + if (symbol) { + if (Template *templ = symbol->asTemplate()) { + if (Symbol *declaration = templ->declaration()) { + if (declaration->isClass() || declaration->isForwardClassDeclaration()) + return true; + } + } + } + return false; +} + +void CheckSymbols::addTypeOrStatic(const QList &candidates, NameAST *ast) +{ + unsigned startToken = ast->firstToken(); + if (DestructorNameAST *dtor = ast->asDestructorName()) + startToken = dtor->identifier_token; + + const Token &tok = tokenAt(startToken); + if (tok.generated()) + return; + + foreach (const LookupItem &r, candidates) { + Symbol *c = r.declaration(); + if (c->isUsingDeclaration()) // skip using declarations... + continue; + else if (c->isUsingNamespaceDirective()) // ... and using namespace directives. + continue; + else if (c->isTypedef() || c->isNamespace() || + c->isClass() || c->isEnum() || isTemplateClass(c) || + c->isForwardClassDeclaration() || c->isTypenameArgument() || c->enclosingEnum() != 0) { + + unsigned line, column; + getTokenStartPosition(startToken, &line, &column); + const unsigned length = tok.length(); + + UseKind kind = SemanticInfo::TypeUse; + + if (c->enclosingEnum() != 0) + kind = SemanticInfo::StaticUse; + + const Use use(line, column, length, kind); + addUse(use); + //qDebug() << "added use" << oo(ast->name) << line << column << length; + break; + } + } +} + +void CheckSymbols::addClassMember(const QList &candidates, NameAST *ast) +{ + unsigned startToken = ast->firstToken(); + if (DestructorNameAST *dtor = ast->asDestructorName()) + startToken = dtor->identifier_token; + + const Token &tok = tokenAt(startToken); + if (tok.generated()) + return; + + foreach (const LookupItem &r, candidates) { + Symbol *c = r.declaration(); + if (! c) + continue; + else if (! c->isDeclaration()) + return; + else if (! (c->enclosingScope() && c->enclosingScope()->isClass())) + return; // shadowed + else if (c->isTypedef() || c->type()->isFunctionType()) + return; // shadowed + + unsigned line, column; + getTokenStartPosition(startToken, &line, &column); + const unsigned length = tok.length(); + + const Use use(line, column, length, SemanticInfo::FieldUse); + addUse(use); + break; + } +} + +void CheckSymbols::addStatic(const QList &candidates, NameAST *ast) +{ + if (ast->asDestructorName() != 0) + return; + + unsigned startToken = ast->firstToken(); + const Token &tok = tokenAt(startToken); + if (tok.generated()) + return; + + foreach (const LookupItem &r, candidates) { + Symbol *c = r.declaration(); + if (! c) + return; + if (c->enclosingScope()->isEnum()) { + unsigned line, column; + getTokenStartPosition(startToken, &line, &column); + const unsigned length = tok.length(); + + const Use use(line, column, length, SemanticInfo::StaticUse); + addUse(use); + //qDebug() << "added use" << oo(ast->name) << line << column << length; + break; + } + } +} + +void CheckSymbols::addVirtualMethod(const QList &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; + + 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; + else if (argumentCount > funTy->argumentCount()) { + if (! funTy->isVariadic()) + continue; + } + + unsigned line, column; + getTokenStartPosition(startToken, &line, &column); + const unsigned length = tok.length(); + + const Use use(line, column, length, SemanticInfo::VirtualMethodUse); + addUse(use); + break; + } +} + +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::maybeType(const Name *name) const +{ + if (name) { + if (const Identifier *ident = name->identifier()) { + const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size()); + if (_potentialTypes.contains(id)) + return true; + } + } + + return false; +} + +bool CheckSymbols::maybeMember(const Name *name) const +{ + if (name) { + if (const Identifier *ident = name->identifier()) { + const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size()); + if (_potentialMembers.contains(id)) + return true; + } + } + + return false; +} + +bool CheckSymbols::maybeStatic(const Name *name) const +{ + if (name) { + if (const Identifier *ident = name->identifier()) { + const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size()); + if (_potentialStatics.contains(id)) + return true; + } + } + + return false; +} + +bool CheckSymbols::maybeVirtualMethod(const Name *name) const +{ + if (name) { + if (const Identifier *ident = name->identifier()) { + const QByteArray id = QByteArray::fromRawData(ident->chars(), ident->size()); + if (_potentialVirtualMethods.contains(id)) + return true; + } + } + + return false; +} + +static bool sortByLinePredicate(const CheckSymbols::Use &lhs, const CheckSymbols::Use &rhs) +{ + return lhs.line < rhs.line; +} + +void CheckSymbols::flush() +{ + _lineOfLastUsage = 0; + + if (_usages.isEmpty()) + return; + + qSort(_usages.begin(), _usages.end(), sortByLinePredicate); + reportResults(_usages); + _usages.clear(); + _usages.reserve(chunkSize); +} diff --git a/src/plugins/cpptools/cppchecksymbols.h b/src/plugins/cpptools/cppchecksymbols.h new file mode 100644 index 0000000000..fb50fcfd52 --- /dev/null +++ b/src/plugins/cpptools/cppchecksymbols.h @@ -0,0 +1,178 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef CPLUSPLUS_CHECKSYMBOLS_H +#define CPLUSPLUS_CHECKSYMBOLS_H + +#include "cppsemanticinfo.h" + +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace CPlusPlus { + +class CheckSymbols: + protected ASTVisitor, + public QRunnable, + public QFutureInterface +{ +public: + virtual ~CheckSymbols(); + + typedef TextEditor::SemanticHighlighter::Result Use; + typedef CppTools::SemanticInfo::UseKind UseKind; + + virtual void run(); + + typedef QFuture Future; + + Future start() + { + this->setRunnable(this); + this->reportStarted(); + Future future = this->future(); + QThreadPool::globalInstance()->start(this, QThread::LowestPriority); + return future; + } + + static Future go(Document::Ptr doc, const LookupContext &context); + + static QMap > chunks(const QFuture &future, int from, int to) + { + QMap > chunks; + + for (int i = from; i < to; ++i) { + const Use use = future.resultAt(i); + if (! use.line) + continue; // skip it, it's an invalid use. + + const int blockNumber = use.line - 1; + chunks[blockNumber].append(use); + } + + return chunks; + } + +protected: + using ASTVisitor::visit; + using ASTVisitor::endVisit; + + CheckSymbols(Document::Ptr doc, const LookupContext &context); + + bool hasVirtualDestructor(Class *klass) const; + bool hasVirtualDestructor(ClassOrNamespace *binding) const; + + bool warning(unsigned line, unsigned column, const QString &text, unsigned length = 0); + bool warning(AST *ast, const QString &text); + + QByteArray textOf(AST *ast) const; + + bool maybeType(const Name *name) const; + bool maybeMember(const Name *name) const; + bool maybeStatic(const Name *name) const; + bool maybeVirtualMethod(const Name *name) const; + + void checkName(NameAST *ast, Scope *scope = 0); + void checkNamespace(NameAST *name); + + void addUse(const Use &use); + void addUse(unsigned tokenIndex, UseKind kind); + void addUse(NameAST *name, UseKind kind); + + void addType(ClassOrNamespace *b, NameAST *ast); + + void addTypeOrStatic(const QList &candidates, NameAST *ast); + void addStatic(const QList &candidates, NameAST *ast); + void addClassMember(const QList &candidates, NameAST *ast); + void addVirtualMethod(const QList &candidates, NameAST *ast, unsigned argumentCount); + + bool isTemplateClass(Symbol *s) const; + + Scope *enclosingScope() const; + FunctionDefinitionAST *enclosingFunctionDefinition(bool skipTopOfStack = false) const; + TemplateDeclarationAST *enclosingTemplateDeclaration() const; + + virtual bool preVisit(AST *); + virtual void postVisit(AST *); + + virtual bool visit(NamespaceAST *); + virtual bool visit(UsingDirectiveAST *); + virtual bool visit(SimpleDeclarationAST *); + virtual bool visit(NamedTypeSpecifierAST *); + virtual bool visit(ElaboratedTypeSpecifierAST *ast); + + virtual bool visit(EnumeratorAST *); + + virtual bool visit(SimpleNameAST *ast); + virtual bool visit(DestructorNameAST *ast); + virtual bool visit(QualifiedNameAST *ast); + virtual bool visit(TemplateIdAST *ast); + + virtual bool visit(TypenameTypeParameterAST *ast); + virtual bool visit(TemplateTypeParameterAST *ast); + + virtual bool visit(FunctionDefinitionAST *ast); + virtual bool visit(MemberAccessAST *ast); + virtual bool visit(CallAST *ast); + + virtual bool visit(MemInitializerAST *ast); + + NameAST *declaratorId(DeclaratorAST *ast) const; + + void flush(); + +private: + Document::Ptr _doc; + LookupContext _context; + TypeOfExpression typeOfExpression; + QString _fileName; + QList _diagnosticMessages; + QSet _potentialTypes; + QSet _potentialMembers; + QSet _potentialVirtualMethods; + QSet _potentialStatics; + QList _astStack; + QVector _usages; + unsigned _lineOfLastUsage; +}; + +} // namespace CPlusPlus + +#endif // CPLUSPLUS_CHECKSYMBOLS_H diff --git a/src/plugins/cpptools/cppcompletionsupport.cpp b/src/plugins/cpptools/cppcompletionsupport.cpp new file mode 100644 index 0000000000..9246708c11 --- /dev/null +++ b/src/plugins/cpptools/cppcompletionsupport.cpp @@ -0,0 +1,72 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "cppcompletionassist.h" +#include "cppcompletionsupport.h" +#include "cppmodelmanager.h" +#include "cpptoolseditorsupport.h" + +#include +#include +#include + +using namespace CPlusPlus; +using namespace CppTools; +using namespace CppTools::Internal; + +CppCompletionSupport::CppCompletionSupport(CppEditorSupport *editorSupport) + : m_editorSupport(editorSupport) +{ + Q_ASSERT(editorSupport); +} + +TextEditor::IAssistInterface *CppCompletionSupport::createAssistInterface(ProjectExplorer::Project *project, + QTextDocument *document, + int position, + TextEditor::AssistReason reason) const +{ + CppModelManagerInterface *modelManager = CppModelManagerInterface::instance(); + QStringList includePaths; + QStringList frameworkPaths; + if (project) { + includePaths = modelManager->projectInfo(project).includePaths; + frameworkPaths = modelManager->projectInfo(project).frameworkPaths; + } + return new CppTools::Internal::CppCompletionAssistInterface( + document, + position, + m_editorSupport->textEditor()->file(), + reason, + modelManager->snapshot(), + includePaths, + frameworkPaths); +} diff --git a/src/plugins/cpptools/cppcompletionsupport.h b/src/plugins/cpptools/cppcompletionsupport.h new file mode 100644 index 0000000000..0435c8a700 --- /dev/null +++ b/src/plugins/cpptools/cppcompletionsupport.h @@ -0,0 +1,77 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef CPPTOOLS_CPPCOMPLETIONSUPPORT_H +#define CPPTOOLS_CPPCOMPLETIONSUPPORT_H + +#include "cpptools_global.h" + +#include + +QT_BEGIN_NAMESPACE +class QTextDocument; +QT_END_NAMESPACE + +namespace Core { +class IFile; +} + +namespace ProjectExplorer { +class Project; +} + +namespace TextEditor { +class IAssistInterface; +} + +namespace CppTools { +namespace Internal { +class CppEditorSupport; +} + +class CPPTOOLS_EXPORT CppCompletionSupport +{ +public: + CppCompletionSupport(Internal::CppEditorSupport *editorSupport); + + TextEditor::IAssistInterface *createAssistInterface(ProjectExplorer::Project *project, + QTextDocument *document, + int position, + TextEditor::AssistReason reason) const; + +private: + Internal::CppEditorSupport *m_editorSupport; +}; + +} // namespace CppTools + +#endif // CPPTOOLS_CPPCOMPLETIONSUPPORT_H diff --git a/src/plugins/cpptools/cpphighlightingsupport.cpp b/src/plugins/cpptools/cpphighlightingsupport.cpp new file mode 100644 index 0000000000..6326b62304 --- /dev/null +++ b/src/plugins/cpptools/cpphighlightingsupport.cpp @@ -0,0 +1,52 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "cppchecksymbols.h" +#include "cpphighlightingsupport.h" +#include "cpptoolseditorsupport.h" + +#include + +using namespace CPlusPlus; +using namespace CppTools; +using namespace CppTools::Internal; + +CppHighlightingSupport::CppHighlightingSupport() +{ +} + +QFuture CppHighlightingSupport::highlightingFuture( + const Document::Ptr &doc, const Snapshot &snapshot) const +{ + LookupContext context(doc, snapshot); + return CheckSymbols::go(doc, context); +} diff --git a/src/plugins/cpptools/cpphighlightingsupport.h b/src/plugins/cpptools/cpphighlightingsupport.h new file mode 100644 index 0000000000..e5ef29d3a2 --- /dev/null +++ b/src/plugins/cpptools/cpphighlightingsupport.h @@ -0,0 +1,62 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef CPPTOOLS_CPPHIGHLIGHTINGSUPPORT_H +#define CPPTOOLS_CPPHIGHLIGHTINGSUPPORT_H + +#include "cpptools_global.h" + +#include +#include + +#include + +namespace CppTools { +namespace Internal { +class CppEditorSupport; +} + +class CPPTOOLS_EXPORT CppHighlightingSupport +{ +public: + typedef TextEditor::SemanticHighlighter::Result Use; + +public: + CppHighlightingSupport(); + + QFuture highlightingFuture(const CPlusPlus::Document::Ptr &doc, + const CPlusPlus::Snapshot &snapshot) const; +}; + +} // namespace CppTools + +#endif // CPPTOOLS_CPPHIGHLIGHTINGSUPPORT_H diff --git a/src/plugins/cpptools/cpplocalsymbols.cpp b/src/plugins/cpptools/cpplocalsymbols.cpp new file mode 100644 index 0000000000..fc4933ef17 --- /dev/null +++ b/src/plugins/cpptools/cpplocalsymbols.cpp @@ -0,0 +1,302 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "cpplocalsymbols.h" +#include "cppsemanticinfo.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace CPlusPlus; +using namespace CppTools; + +namespace { + +class FindLocalSymbols: protected ASTVisitor +{ + Scope *_functionScope; + Document::Ptr _doc; + +public: + FindLocalSymbols(Document::Ptr doc) + : ASTVisitor(doc->translationUnit()), _doc(doc), hasD(false), hasQ(false) + { } + + // local and external uses. + SemanticInfo::LocalUseMap localUses; + bool hasD; + bool hasQ; + + void operator()(DeclarationAST *ast) + { + localUses.clear(); + + if (!ast) + return; + + if (FunctionDefinitionAST *def = ast->asFunctionDefinition()) { + if (def->symbol) { + _functionScope = def->symbol; + accept(ast); + } + } else if (ObjCMethodDeclarationAST *decl = ast->asObjCMethodDeclaration()) { + if (decl->method_prototype->symbol) { + _functionScope = decl->method_prototype->symbol; + accept(ast); + } + } + } + +protected: + using ASTVisitor::visit; + using ASTVisitor::endVisit; + + void enterScope(Scope *scope) + { + _scopeStack.append(scope); + + for (unsigned i = 0; i < scope->memberCount(); ++i) { + if (Symbol *member = scope->memberAt(i)) { + if (member->isTypedef()) + continue; + else if (! member->isGenerated() && (member->isDeclaration() || member->isArgument())) { + if (member->name() && member->name()->isNameId()) { + const Identifier *id = member->identifier(); + unsigned line, column; + getTokenStartPosition(member->sourceLocation(), &line, &column); + localUses[member].append(SemanticInfo::Use(line, column, id->size(), SemanticInfo::LocalUse)); + } + } + } + } + } + + bool checkLocalUse(NameAST *nameAst, unsigned firstToken) + { + if (SimpleNameAST *simpleName = nameAst->asSimpleName()) { + const Identifier *id = identifier(simpleName->identifier_token); + for (int i = _scopeStack.size() - 1; i != -1; --i) { + if (Symbol *member = _scopeStack.at(i)->find(id)) { + if (member->isTypedef() || + !(member->isDeclaration() || member->isArgument())) + continue; + else if (!member->isGenerated() && (member->sourceLocation() < firstToken || member->enclosingScope()->isFunction())) { + unsigned line, column; + getTokenStartPosition(simpleName->identifier_token, &line, &column); + localUses[member].append(SemanticInfo::Use(line, column, id->size(), SemanticInfo::LocalUse)); + return false; + } + } + } + } + + return true; + } + + virtual bool visit(IdExpressionAST *ast) + { + return checkLocalUse(ast->name, ast->firstToken()); + } + + virtual bool visit(SizeofExpressionAST *ast) + { + if (ast->expression && ast->expression->asTypeId()) { + TypeIdAST *typeId = ast->expression->asTypeId(); + if (!typeId->declarator && typeId->type_specifier_list && !typeId->type_specifier_list->next) { + if (NamedTypeSpecifierAST *namedTypeSpec = typeId->type_specifier_list->value->asNamedTypeSpecifier()) { + if (checkLocalUse(namedTypeSpec->name, namedTypeSpec->firstToken())) + return false; + } + } + } + + return true; + } + + virtual bool visit(CastExpressionAST *ast) + { + if (ast->expression && ast->expression->asUnaryExpression()) { + TypeIdAST *typeId = ast->type_id->asTypeId(); + if (typeId && !typeId->declarator && typeId->type_specifier_list && !typeId->type_specifier_list->next) { + if (NamedTypeSpecifierAST *namedTypeSpec = typeId->type_specifier_list->value->asNamedTypeSpecifier()) { + if (checkLocalUse(namedTypeSpec->name, namedTypeSpec->firstToken())) { + accept(ast->expression); + return false; + } + } + } + } + + return true; + } + + virtual bool visit(QtMemberDeclarationAST *ast) + { + if (tokenKind(ast->q_token) == T_Q_D) + hasD = true; + else + hasQ = true; + + return true; + } + + virtual bool visit(FunctionDefinitionAST *ast) + { + if (ast->symbol) + enterScope(ast->symbol); + return true; + } + + virtual void endVisit(FunctionDefinitionAST *ast) + { + if (ast->symbol) + _scopeStack.removeLast(); + } + + virtual bool visit(CompoundStatementAST *ast) + { + if (ast->symbol) + enterScope(ast->symbol); + return true; + } + + virtual void endVisit(CompoundStatementAST *ast) + { + if (ast->symbol) + _scopeStack.removeLast(); + } + + virtual bool visit(IfStatementAST *ast) + { + if (ast->symbol) + enterScope(ast->symbol); + return true; + } + + virtual void endVisit(IfStatementAST *ast) + { + if (ast->symbol) + _scopeStack.removeLast(); + } + + virtual bool visit(WhileStatementAST *ast) + { + if (ast->symbol) + enterScope(ast->symbol); + return true; + } + + virtual void endVisit(WhileStatementAST *ast) + { + if (ast->symbol) + _scopeStack.removeLast(); + } + + virtual bool visit(ForStatementAST *ast) + { + if (ast->symbol) + enterScope(ast->symbol); + return true; + } + + virtual void endVisit(ForStatementAST *ast) + { + if (ast->symbol) + _scopeStack.removeLast(); + } + + virtual bool visit(ForeachStatementAST *ast) + { + if (ast->symbol) + enterScope(ast->symbol); + return true; + } + + virtual void endVisit(ForeachStatementAST *ast) + { + if (ast->symbol) + _scopeStack.removeLast(); + } + + virtual bool visit(SwitchStatementAST *ast) + { + if (ast->symbol) + enterScope(ast->symbol); + return true; + } + + virtual void endVisit(SwitchStatementAST *ast) + { + if (ast->symbol) + _scopeStack.removeLast(); + } + + virtual bool visit(CatchClauseAST *ast) + { + if (ast->symbol) + enterScope(ast->symbol); + return true; + } + + virtual void endVisit(CatchClauseAST *ast) + { + if (ast->symbol) + _scopeStack.removeLast(); + } + + virtual bool visit(ExpressionOrDeclarationStatementAST *ast) + { + accept(ast->declaration); + return false; + } + +private: + QList _scopeStack; +}; + +} // end of anonymous namespace + + +LocalSymbols::LocalSymbols(CPlusPlus::Document::Ptr doc, CPlusPlus::DeclarationAST *ast) +{ + FindLocalSymbols findLocalSymbols(doc); + findLocalSymbols(ast); + hasD = findLocalSymbols.hasD; + hasQ = findLocalSymbols.hasQ; + uses = findLocalSymbols.localUses; +} diff --git a/src/plugins/cpptools/cpplocalsymbols.h b/src/plugins/cpptools/cpplocalsymbols.h new file mode 100644 index 0000000000..c4325f6d9f --- /dev/null +++ b/src/plugins/cpptools/cpplocalsymbols.h @@ -0,0 +1,58 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef CPPLOCALSYMBOLS_H +#define CPPLOCALSYMBOLS_H + +#include "cpptools_global.h" +#include "cppsemanticinfo.h" + +#include +#include + +namespace CppTools { + +class CPPTOOLS_EXPORT LocalSymbols +{ + Q_DISABLE_COPY(LocalSymbols) + +public: + LocalSymbols(CPlusPlus::Document::Ptr doc, CPlusPlus::DeclarationAST *ast); + + bool hasD; + bool hasQ; + SemanticInfo::LocalUseMap uses; +}; + +} // namespace CppTools + +#endif // CPPLOCALSYMBOLS_H diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index 4000228aae..7e82347594 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -1308,6 +1308,21 @@ void CppModelManager::finishedRefreshingSourceFiles(const QStringList &files) emit sourceFilesRefreshed(files); } +CppCompletionSupport *CppModelManager::completionSupport(Core::IEditor *editor) const +{ + if (CppEditorSupport *es = editorSupport(qobject_cast(editor))) + return es->completionSupport(); + else + return 0; +} + +CppHighlightingSupport *CppModelManager::highlightingSupport(Core::IEditor *editor) const +{ + if (CppEditorSupport *es = editorSupport(qobject_cast(editor))) + return es->highlightingSupport(); + else + return 0; +} void CppModelManager::setExtraDiagnostics(const QString &fileName, int kind, const QList &diagnostics) diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index 6b8374524b..e7d0675de1 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -131,9 +131,11 @@ public: virtual QList extraDiagnostics( const QString &fileName, int key = AllExtraDiagnostics) const; - void finishedRefreshingSourceFiles(const QStringList &files); + virtual CppCompletionSupport *completionSupport(Core::IEditor *editor) const; + virtual CppHighlightingSupport *highlightingSupport(Core::IEditor *editor) const; + Q_SIGNALS: void projectPathChanged(const QString &projectPath); diff --git a/src/plugins/cpptools/cppsemanticinfo.cpp b/src/plugins/cpptools/cppsemanticinfo.cpp new file mode 100644 index 0000000000..761138459a --- /dev/null +++ b/src/plugins/cpptools/cppsemanticinfo.cpp @@ -0,0 +1,40 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#include "cppsemanticinfo.h" + +using namespace CppTools; + +SemanticInfo::SemanticInfo() + : revision(0), hasQ(false), hasD(false), forced(false) +{ +} diff --git a/src/plugins/cpptools/cppsemanticinfo.h b/src/plugins/cpptools/cppsemanticinfo.h new file mode 100644 index 0000000000..915ffad1f5 --- /dev/null +++ b/src/plugins/cpptools/cppsemanticinfo.h @@ -0,0 +1,74 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** +** GNU Lesser General Public License Usage +** +** 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. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef CPPSEMANTICINFO_H +#define CPPSEMANTICINFO_H + +#include "cpptools_global.h" + +#include +#include +#include +#include + +namespace CppTools { + +class CPPTOOLS_EXPORT SemanticInfo +{ +public: + enum UseKind { + TypeUse = 0, + LocalUse, + FieldUse, + StaticUse, + VirtualMethodUse + }; + typedef TextEditor::SemanticHighlighter::Result Use; + + typedef QHash > LocalUseMap; + typedef QHashIterator > LocalUseIterator; + + SemanticInfo(); + + unsigned revision; + bool hasQ: 1; + bool hasD: 1; + bool forced: 1; + CPlusPlus::Snapshot snapshot; + CPlusPlus::Document::Ptr doc; + LocalUseMap localUses; + QList objcKeywords; +}; + +} // namespace CppTools + +#endif // CPPSEMANTICINFO_H diff --git a/src/plugins/cpptools/cpptools.pro b/src/plugins/cpptools/cpptools.pro index 8bce1abd05..e685f307b7 100644 --- a/src/plugins/cpptools/cpptools.pro +++ b/src/plugins/cpptools/cpptools.pro @@ -38,7 +38,12 @@ HEADERS += completionsettingspage.h \ cpptoolsreuse.h \ doxygengenerator.h \ commentssettings.h \ - symbolfinder.h + symbolfinder.h \ + cppcompletionsupport.h \ + cpphighlightingsupport.h \ + cppchecksymbols.h \ + cpplocalsymbols.h \ + cppsemanticinfo.h SOURCES += completionsettingspage.cpp \ cppclassesfilter.cpp \ @@ -68,7 +73,12 @@ SOURCES += completionsettingspage.cpp \ cpptoolsreuse.cpp \ doxygengenerator.cpp \ commentssettings.cpp \ - symbolfinder.cpp + symbolfinder.cpp \ + cppcompletionsupport.cpp \ + cpphighlightingsupport.cpp \ + cppchecksymbols.cpp \ + cpplocalsymbols.cpp \ + cppsemanticinfo.cpp FORMS += completionsettingspage.ui \ cppfilesettingspage.ui \ diff --git a/src/plugins/cpptools/cpptoolseditorsupport.cpp b/src/plugins/cpptools/cpptoolseditorsupport.cpp index ee69b4fabf..3f3c3c8a50 100644 --- a/src/plugins/cpptools/cpptoolseditorsupport.cpp +++ b/src/plugins/cpptools/cpptoolseditorsupport.cpp @@ -30,6 +30,8 @@ ** **************************************************************************/ +#include "cppcompletionsupport.h" +#include "cpphighlightingsupport.h" #include "cpptoolseditorsupport.h" #include "cppmodelmanager.h" @@ -44,13 +46,16 @@ #include +using namespace CppTools; using namespace CppTools::Internal; using namespace CPlusPlus; CppEditorSupport::CppEditorSupport(CppModelManager *modelManager) : QObject(modelManager), _modelManager(modelManager), - _updateDocumentInterval(UPDATE_DOCUMENT_DEFAULT_INTERVAL) + _updateDocumentInterval(UPDATE_DOCUMENT_DEFAULT_INTERVAL), + m_completionSupport(new CppCompletionSupport(this)), + m_highlightingSupport(new CppHighlightingSupport) { _revision = 0; @@ -98,6 +103,16 @@ unsigned CppEditorSupport::editorRevision() const return 0; } +CppTools::CppCompletionSupport *CppEditorSupport::completionSupport() const +{ + return m_completionSupport.data(); +} + +CppHighlightingSupport *CppEditorSupport::highlightingSupport() const +{ + return m_highlightingSupport.data(); +} + int CppEditorSupport::updateDocumentInterval() const { return _updateDocumentInterval; } diff --git a/src/plugins/cpptools/cpptoolseditorsupport.h b/src/plugins/cpptools/cpptoolseditorsupport.h index 2c2199d00f..353dd7bdcd 100644 --- a/src/plugins/cpptools/cpptoolseditorsupport.h +++ b/src/plugins/cpptools/cpptoolseditorsupport.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,10 @@ namespace TextEditor { } // namespace TextEditor namespace CppTools { + +class CppCompletionSupport; +class CppHighlightingSupport; + namespace Internal { class CppModelManager; @@ -77,6 +82,9 @@ public: QString contents(); unsigned editorRevision() const; + CppCompletionSupport *completionSupport() const; + CppHighlightingSupport *highlightingSupport() const; + Q_SIGNALS: void contentsChanged(); @@ -94,6 +102,8 @@ private: QFuture _documentParser; QString _cachedContents; unsigned _revision; + QScopedPointer m_completionSupport; + QScopedPointer m_highlightingSupport; }; } // namespace Internal -- cgit v1.2.1