summaryrefslogtreecommitdiff
path: root/src/plugins/cpptools
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/cpptools')
-rw-r--r--src/plugins/cpptools/cppchecksymbols.cpp1110
-rw-r--r--src/plugins/cpptools/cppchecksymbols.h178
-rw-r--r--src/plugins/cpptools/cppcompletionsupport.cpp72
-rw-r--r--src/plugins/cpptools/cppcompletionsupport.h77
-rw-r--r--src/plugins/cpptools/cpphighlightingsupport.cpp52
-rw-r--r--src/plugins/cpptools/cpphighlightingsupport.h62
-rw-r--r--src/plugins/cpptools/cpplocalsymbols.cpp302
-rw-r--r--src/plugins/cpptools/cpplocalsymbols.h58
-rw-r--r--src/plugins/cpptools/cppmodelmanager.cpp15
-rw-r--r--src/plugins/cpptools/cppmodelmanager.h4
-rw-r--r--src/plugins/cpptools/cppsemanticinfo.cpp40
-rw-r--r--src/plugins/cpptools/cppsemanticinfo.h74
-rw-r--r--src/plugins/cpptools/cpptools.pro14
-rw-r--r--src/plugins/cpptools/cpptoolseditorsupport.cpp17
-rw-r--r--src/plugins/cpptools/cpptoolseditorsupport.h10
15 files changed, 2081 insertions, 4 deletions
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 <cplusplus/Overview.h>
+
+#include <Names.h>
+#include <Literals.h>
+#include <Symbols.h>
+#include <TranslationUnit.h>
+#include <Scope.h>
+#include <AST.h>
+#include <SymbolVisitor.h>
+
+#include <utils/qtcassert.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QThreadPool>
+#include <QtCore/QDebug>
+
+#include <qtconcurrent/runextensions.h>
+
+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<QByteArray> _types;
+ QSet<QByteArray> _members;
+ QSet<QByteArray> _virtualMethods;
+ QSet<QByteArray> _statics;
+ bool _mainDocument;
+
+public:
+ CollectSymbols(Document::Ptr doc, const Snapshot &snapshot)
+ : _doc(doc), _snapshot(snapshot), _mainDocument(false)
+ {
+ QSet<Namespace *> processed;
+ process(doc, &processed);
+ }
+
+ const QSet<QByteArray> &types() const
+ {
+ return _types;
+ }
+
+ const QSet<QByteArray> &members() const
+ {
+ return _members;
+ }
+
+ const QSet<QByteArray> &virtualMethods() const
+ {
+ return _virtualMethods;
+ }
+
+ const QSet<QByteArray> &statics() const
+ {
+ return _statics;
+ }
+
+protected:
+ void process(Document::Ptr doc, QSet<Namespace *> *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<LookupItem> 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<LookupItem> 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<LookupItem> 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<ClassOrNamespace *> processed;
+ QList<ClassOrNamespace *> 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<LookupItem> candidates = _context.lookup(ast->name, scope);
+ addTypeOrStatic(candidates, ast);
+ } else if (maybeMember(ast->name)) {
+ const QList<LookupItem> 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<SemanticInfo::Use> &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<LookupItem> &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<LookupItem> &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<LookupItem> &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<LookupItem> &candidates, NameAST *ast, unsigned argumentCount)
+{
+ unsigned startToken = ast->firstToken();
+ if (DestructorNameAST *dtor = ast->asDestructorName())
+ startToken = dtor->identifier_token;
+
+ const Token &tok = tokenAt(startToken);
+ if (tok.generated())
+ return;
+
+ 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 <cplusplus/CppDocument.h>
+#include <cplusplus/LookupContext.h>
+#include <cplusplus/TypeOfExpression.h>
+
+#include <texteditor/semantichighlighter.h>
+
+#include <ASTVisitor.h>
+#include <QtCore/QSet>
+#include <QtCore/QFuture>
+#include <QtCore/QtConcurrentRun>
+
+namespace CPlusPlus {
+
+class CheckSymbols:
+ protected ASTVisitor,
+ public QRunnable,
+ public QFutureInterface<TextEditor::SemanticHighlighter::Result>
+{
+public:
+ virtual ~CheckSymbols();
+
+ typedef TextEditor::SemanticHighlighter::Result Use;
+ typedef CppTools::SemanticInfo::UseKind UseKind;
+
+ virtual void run();
+
+ typedef QFuture<Use> 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<int, QVector<Use> > chunks(const QFuture<Use> &future, int from, int to)
+ {
+ QMap<int, QVector<Use> > 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<LookupItem> &candidates, NameAST *ast);
+ void addStatic(const QList<LookupItem> &candidates, NameAST *ast);
+ void addClassMember(const QList<LookupItem> &candidates, NameAST *ast);
+ void addVirtualMethod(const QList<LookupItem> &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<Document::DiagnosticMessage> _diagnosticMessages;
+ QSet<QByteArray> _potentialTypes;
+ QSet<QByteArray> _potentialMembers;
+ QSet<QByteArray> _potentialVirtualMethods;
+ QSet<QByteArray> _potentialStatics;
+ QList<AST *> _astStack;
+ QVector<Use> _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 <coreplugin/ifile.h>
+#include <projectexplorer/project.h>
+#include <texteditor/codeassist/iassistinterface.h>
+
+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 <texteditor/codeassist/assistenums.h>
+
+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 <cplusplus/LookupContext.h>
+
+using namespace CPlusPlus;
+using namespace CppTools;
+using namespace CppTools::Internal;
+
+CppHighlightingSupport::CppHighlightingSupport()
+{
+}
+
+QFuture<CppHighlightingSupport::Use> 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 <cplusplus/CppDocument.h>
+#include <texteditor/semantichighlighter.h>
+
+#include <QtCore/QFuture>
+
+namespace CppTools {
+namespace Internal {
+class CppEditorSupport;
+}
+
+class CPPTOOLS_EXPORT CppHighlightingSupport
+{
+public:
+ typedef TextEditor::SemanticHighlighter::Result Use;
+
+public:
+ CppHighlightingSupport();
+
+ QFuture<Use> 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 <cplusplus/CppDocument.h>
+#include <ASTVisitor.h>
+#include <AST.h>
+#include <Scope.h>
+#include <Symbols.h>
+#include <CoreTypes.h>
+#include <Names.h>
+#include <Literals.h>
+
+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<Scope *> _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 <cplusplus/CppDocument.h>
+#include <ASTfwd.h>
+
+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<TextEditor::ITextEditor *>(editor)))
+ return es->completionSupport();
+ else
+ return 0;
+}
+
+CppHighlightingSupport *CppModelManager::highlightingSupport(Core::IEditor *editor) const
+{
+ if (CppEditorSupport *es = editorSupport(qobject_cast<TextEditor::ITextEditor *>(editor)))
+ return es->highlightingSupport();
+ else
+ return 0;
+}
void CppModelManager::setExtraDiagnostics(const QString &fileName, int kind,
const QList<Document::DiagnosticMessage> &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<CPlusPlus::Document::DiagnosticMessage> 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 <cplusplus/CppDocument.h>
+#include <cplusplus/LookupContext.h>
+#include <texteditor/semantichighlighter.h>
+#include <QtCore/QHash>
+
+namespace CppTools {
+
+class CPPTOOLS_EXPORT SemanticInfo
+{
+public:
+ enum UseKind {
+ TypeUse = 0,
+ LocalUse,
+ FieldUse,
+ StaticUse,
+ VirtualMethodUse
+ };
+ typedef TextEditor::SemanticHighlighter::Result Use;
+
+ typedef QHash<CPlusPlus::Symbol *, QList<Use> > LocalUseMap;
+ typedef QHashIterator<CPlusPlus::Symbol *, QList<Use> > LocalUseIterator;
+
+ SemanticInfo();
+
+ unsigned revision;
+ bool hasQ: 1;
+ bool hasD: 1;
+ bool forced: 1;
+ CPlusPlus::Snapshot snapshot;
+ CPlusPlus::Document::Ptr doc;
+ LocalUseMap localUses;
+ QList<Use> 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 <QtCore/QTimer>
+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 <QtCore/QObject>
#include <QtCore/QPointer>
#include <QtCore/QFuture>
+#include <QtCore/QScopedPointer>
#include <QtCore/QSharedPointer>
#include <QtGui/QTextCursor>
@@ -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<void> _documentParser;
QString _cachedContents;
unsigned _revision;
+ QScopedPointer<CppCompletionSupport> m_completionSupport;
+ QScopedPointer<CppHighlightingSupport> m_highlightingSupport;
};
} // namespace Internal