2010-07-15 16:03:48 +02:00
|
|
|
/**************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
|
**
|
|
|
|
|
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
|
|
|
**
|
|
|
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
|
|
|
**
|
|
|
|
|
** Commercial Usage
|
|
|
|
|
**
|
|
|
|
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
|
|
|
|
** accordance with the Qt Commercial License Agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and Nokia.
|
|
|
|
|
**
|
|
|
|
|
** GNU Lesser General Public License Usage
|
|
|
|
|
**
|
|
|
|
|
** Alternatively, 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.
|
|
|
|
|
**
|
|
|
|
|
** If you are unsure which license is appropriate for your use, please
|
|
|
|
|
** contact the sales department at http://qt.nokia.com/contact.
|
|
|
|
|
**
|
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
|
|
#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 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->members();
|
|
|
|
|
accept(ast);
|
|
|
|
|
}
|
|
|
|
|
} else if (ObjCMethodDeclarationAST *decl = ast->asObjCMethodDeclaration()) {
|
|
|
|
|
if (decl->method_prototype->symbol) {
|
|
|
|
|
_functionScope = decl->method_prototype->symbol->members();
|
|
|
|
|
accept(ast);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
using ASTVisitor::visit;
|
|
|
|
|
|
|
|
|
|
bool findMember(Scope *scope, NameAST *ast, unsigned line, unsigned column)
|
|
|
|
|
{
|
|
|
|
|
if (! (ast && ast->name))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
const Identifier *id = ast->name->identifier();
|
|
|
|
|
|
|
|
|
|
if (scope) {
|
|
|
|
|
for (Symbol *member = scope->lookat(id); member; member = member->next()) {
|
|
|
|
|
if (member->identifier() != id)
|
|
|
|
|
continue;
|
|
|
|
|
else if (member->line() < line || (member->line() == line && member->column() <= column)) {
|
|
|
|
|
localUses[member].append(SemanticInfo::Use(line, column, id->size(), SemanticInfo::Use::Local));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void searchUsesInTemplateArguments(NameAST *name)
|
|
|
|
|
{
|
|
|
|
|
if (! name)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
else if (TemplateIdAST *template_id = name->asTemplateId()) {
|
|
|
|
|
for (TemplateArgumentListAST *it = template_id->template_argument_list; it; it = it->next) {
|
|
|
|
|
accept(it->value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool visit(SimpleNameAST *ast)
|
|
|
|
|
{ return findMemberForToken(ast->firstToken(), ast); }
|
|
|
|
|
|
|
|
|
|
bool findMemberForToken(unsigned tokenIdx, NameAST *ast)
|
|
|
|
|
{
|
|
|
|
|
const Token &tok = tokenAt(tokenIdx);
|
|
|
|
|
if (tok.generated())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
unsigned line, column;
|
|
|
|
|
getTokenStartPosition(tokenIdx, &line, &column);
|
|
|
|
|
|
|
|
|
|
Scope *scope = _doc->scopeAt(line, column);
|
|
|
|
|
|
|
|
|
|
while (scope) {
|
2010-08-05 17:06:16 +02:00
|
|
|
if (scope->isPrototypeScope()) {
|
2010-07-15 16:03:48 +02:00
|
|
|
Function *fun = scope->owner()->asFunction();
|
|
|
|
|
if (findMember(fun->members(), ast, line, column))
|
|
|
|
|
return false;
|
2010-08-05 17:02:25 +02:00
|
|
|
else if (findMember(fun->members(), ast, line, column))
|
2010-07-15 16:03:48 +02:00
|
|
|
return false;
|
|
|
|
|
} else if (scope->isObjCMethodScope()) {
|
|
|
|
|
ObjCMethod *method = scope->owner()->asObjCMethod();
|
|
|
|
|
if (findMember(method->members(), ast, line, column))
|
|
|
|
|
return false;
|
|
|
|
|
else if (findMember(method->arguments(), ast, line, column))
|
|
|
|
|
return false;
|
|
|
|
|
} else if (scope->isBlockScope()) {
|
|
|
|
|
if (findMember(scope, ast, line, column))
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scope = scope->enclosingScope();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-03 13:01:24 +02:00
|
|
|
virtual bool visit(MemInitializerAST *ast)
|
|
|
|
|
{
|
|
|
|
|
accept(ast->expression_list);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-15 16:03:48 +02:00
|
|
|
virtual bool visit(TemplateIdAST *ast)
|
|
|
|
|
{
|
|
|
|
|
for (TemplateArgumentListAST *arg = ast->template_argument_list; arg; arg = arg->next)
|
|
|
|
|
accept(arg->value);
|
|
|
|
|
|
|
|
|
|
const Token &tok = tokenAt(ast->identifier_token);
|
|
|
|
|
if (tok.generated())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
unsigned line, column;
|
|
|
|
|
getTokenStartPosition(ast->firstToken(), &line, &column);
|
|
|
|
|
|
|
|
|
|
Scope *scope = _doc->scopeAt(line, column);
|
|
|
|
|
|
|
|
|
|
while (scope) {
|
2010-08-05 17:06:16 +02:00
|
|
|
if (scope->isPrototypeScope()) {
|
2010-07-15 16:03:48 +02:00
|
|
|
Function *fun = scope->owner()->asFunction();
|
|
|
|
|
if (findMember(fun->members(), ast, line, column))
|
|
|
|
|
return false;
|
2010-08-05 17:02:25 +02:00
|
|
|
else if (fun->block() && findMember(fun->block()->members(), ast, line, column))
|
2010-07-15 16:03:48 +02:00
|
|
|
return false;
|
|
|
|
|
} else if (scope->isBlockScope()) {
|
|
|
|
|
if (findMember(scope, ast, line, column))
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scope = scope->enclosingScope();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool visit(QualifiedNameAST *ast)
|
|
|
|
|
{
|
|
|
|
|
for (NestedNameSpecifierListAST *it = ast->nested_name_specifier_list; it; it = it->next)
|
|
|
|
|
searchUsesInTemplateArguments(it->value->class_or_namespace_name);
|
|
|
|
|
|
|
|
|
|
searchUsesInTemplateArguments(ast->unqualified_name);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool visit(MemberAccessAST *ast)
|
|
|
|
|
{
|
|
|
|
|
// accept only the base expression
|
|
|
|
|
accept(ast->base_expression);
|
|
|
|
|
// and ignore the member name.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool visit(ElaboratedTypeSpecifierAST *)
|
|
|
|
|
{
|
|
|
|
|
// ### template args
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool visit(ClassSpecifierAST *)
|
|
|
|
|
{
|
|
|
|
|
// ### template args
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool visit(EnumSpecifierAST *)
|
|
|
|
|
{
|
|
|
|
|
// ### template args
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool visit(UsingDirectiveAST *)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool visit(UsingAST *ast)
|
|
|
|
|
{
|
|
|
|
|
accept(ast->name);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool visit(QtMemberDeclarationAST *ast)
|
|
|
|
|
{
|
|
|
|
|
if (tokenKind(ast->q_token) == T_Q_D)
|
|
|
|
|
hasD = true;
|
|
|
|
|
else
|
|
|
|
|
hasQ = true;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool visit(ExpressionOrDeclarationStatementAST *ast)
|
|
|
|
|
{
|
|
|
|
|
accept(ast->declaration);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool visit(FunctionDeclaratorAST *ast)
|
|
|
|
|
{
|
|
|
|
|
accept(ast->parameters);
|
|
|
|
|
|
|
|
|
|
for (SpecifierListAST *it = ast->cv_qualifier_list; it; it = it->next)
|
|
|
|
|
accept(it->value);
|
|
|
|
|
|
|
|
|
|
accept(ast->exception_specification);
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool visit(ObjCMethodPrototypeAST *ast)
|
|
|
|
|
{
|
|
|
|
|
accept(ast->argument_list);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual bool visit(ObjCMessageArgumentDeclarationAST *ast)
|
|
|
|
|
{
|
|
|
|
|
accept(ast->param_name);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // 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;
|
|
|
|
|
}
|