Commit 0f301f86 authored by Roberto Raggi's avatar Roberto Raggi

New implementation of CPlusPlus::FindUsages

parent f72a080d
......@@ -29,29 +29,27 @@
#include "FindUsages.h"
#include "Overview.h"
#include <AST.h>
#include <TranslationUnit.h>
#include <Control.h>
#include <Literals.h>
#include <Names.h>
#include <Scope.h>
#include <Symbols.h>
#include <AST.h>
#include <TranslationUnit.h>
#include <QtCore/QDir>
#include <QtCore/QDebug>
#include <CoreTypes.h>
#include <Literals.h>
#include <Scope.h>
#include <QDebug>
using namespace CPlusPlus;
FindUsages::FindUsages(Document::Ptr doc, const Snapshot &snapshot)
: ASTVisitor(doc->translationUnit()),
_id(0),
_declSymbol(0),
_doc(doc),
_snapshot(snapshot),
_context(doc, snapshot),
_source(_doc->source()),
_sem(doc->translationUnit()),
_inSimpleDeclaration(0),
_inQProperty(false)
_currentScope(0)
{
_snapshot.insert(_doc);
typeofExpression.init(_doc, _snapshot, _context.bindings());
......@@ -59,13 +57,13 @@ FindUsages::FindUsages(Document::Ptr doc, const Snapshot &snapshot)
FindUsages::FindUsages(const LookupContext &context)
: ASTVisitor(context.thisDocument()->translationUnit()),
_id(0),
_declSymbol(0),
_doc(context.thisDocument()),
_snapshot(context.snapshot()),
_context(context),
_source(_doc->source()),
_sem(_doc->translationUnit()),
_inSimpleDeclaration(0),
_inQProperty(false)
_currentScope(0)
{
typeofExpression.init(_doc, _snapshot, _context.bindings());
}
......@@ -89,14 +87,14 @@ void FindUsages::operator()(Symbol *symbol)
_processed.clear();
_references.clear();
_usages.clear();
_declSymbol = symbol;
_declSymbolFullyQualifiedName = LookupContext::fullyQualifiedName(symbol);
_inSimpleDeclaration = 0;
_inQProperty = false;
// get the canonical id
_id = _doc->control()->findOrInsertIdentifier(_id->chars(), _id->size());
accept(_doc->translationUnit()->ast());
if (AST *ast = _doc->translationUnit()->ast())
translationUnit(ast->asTranslationUnit());
}
QString FindUsages::matchingLine(const Token &tk) const
......@@ -120,6 +118,26 @@ QString FindUsages::matchingLine(const Token &tk) const
return matchingLine;
}
void FindUsages::reportResult(unsigned tokenIndex, const Name *name, Scope *scope)
{
if (! (tokenIndex && name != 0))
return;
if (name->identifier() != _id)
return;
if (! scope)
scope = _currentScope;
const QList<LookupItem> candidates = _context.lookup(name, scope);
reportResult(tokenIndex, candidates);
}
void FindUsages::reportResult(unsigned tokenIndex, const Identifier *id, Scope *scope)
{
reportResult(tokenIndex, control()->nameId(id), scope);
}
void FindUsages::reportResult(unsigned tokenIndex, const QList<LookupItem> &candidates)
{
if (_processed.contains(tokenIndex))
......@@ -185,13 +203,18 @@ bool FindUsages::compareName(const Name *name, const Name *other)
return false;
}
bool FindUsages::checkCandidates(const QList<LookupItem> &candidates) const
{
for (int i = candidates.size() - 1; i != -1; --i) {
const LookupItem &r = candidates.at(i);
if (Symbol *s = r.declaration()) {
if (_declSymbol->scope() && (_declSymbol->scope()->isPrototypeScope() || _declSymbol->scope()->isBlockScope())) {
if (s->scope() != _declSymbol->scope())
return false;
}
if (compareFullyQualifiedName(LookupContext::fullyQualifiedName(s), _declSymbolFullyQualifiedName))
return true;
}
......@@ -200,367 +223,1911 @@ bool FindUsages::checkCandidates(const QList<LookupItem> &candidates) const
return false;
}
void FindUsages::ensureNameIsValid(NameAST *ast)
void FindUsages::checkExpression(unsigned startToken, unsigned endToken, Scope *scope)
{
if (ast && ! ast->name)
ast->name = _sem.check(ast, /*scope = */ 0);
const unsigned begin = tokenAt(startToken).begin();
const unsigned end = tokenAt(endToken).end();
const QString expression = _source.mid(begin, end - begin);
// qDebug() << "*** check expression:" << expression;
if (! scope)
scope = _currentScope;
const QList<LookupItem> results = typeofExpression(expression, scope,
TypeOfExpression::Preprocess);
reportResult(endToken, results);
}
bool FindUsages::visit(FunctionDefinitionAST *ast)
Scope *FindUsages::switchScope(ScopedSymbol *symbol)
{
AST *thisFunction = _astStack.takeLast();
accept(ast->decl_specifier_list);
_astStack.append(thisFunction);
if (! symbol)
return _currentScope; // ### assert?
accept(ast->declarator);
accept(ast->ctor_initializer);
accept(ast->function_body);
return false;
return switchScope(symbol->members());
}
bool FindUsages::visit(NamespaceAST *ast)
Scope *FindUsages::switchScope(Scope *scope)
{
const Identifier *id = identifier(ast->identifier_token);
if (id == _id && ast->symbol) {
const QList<LookupItem> candidates = _context.lookup(ast->symbol->name(), enclosingScope());
reportResult(ast->identifier_token, candidates);
}
return true;
Scope *previousScope = _currentScope;
_currentScope = scope;
return previousScope;
}
bool FindUsages::visit(MemInitializerAST *ast)
void FindUsages::statement(StatementAST *ast)
{
if (ast->name && ast->name->asSimpleName() != 0) {
ensureNameIsValid(ast->name);
accept(ast);
}
SimpleNameAST *simple = ast->name->asSimpleName();
if (identifier(simple->identifier_token) == _id) {
const QList<LookupItem> candidates = _context.lookup(simple->name, enclosingScope());
reportResult(simple->identifier_token, candidates);
}
}
accept(ast->expression_list);
return false;
void FindUsages::expression(ExpressionAST *ast)
{
accept(ast);
}
bool FindUsages::visit(MemberAccessAST *ast)
void FindUsages::declaration(DeclarationAST *ast)
{
if (ast->member_name) {
if (SimpleNameAST *simple = ast->member_name->asSimpleName()) {
if (identifier(simple->identifier_token) == _id) {
checkExpression(ast->firstToken(), simple->identifier_token);
return false;
}
}
accept(ast);
}
const Name *FindUsages::name(NameAST *ast)
{
if (ast) {
accept(ast);
return ast->name;
}
return true;
return 0;
}
void FindUsages::checkExpression(unsigned startToken, unsigned endToken)
void FindUsages::specifier(SpecifierAST *ast)
{
const unsigned begin = tokenAt(startToken).begin();
const unsigned end = tokenAt(endToken).end();
const QString expression = _source.mid(begin, end - begin);
// qDebug() << "*** check expression:" << expression;
accept(ast);
}
unsigned line, column;
getTokenStartPosition(startToken, &line, &column);
Scope *scope = _doc->scopeAt(line, column);
void FindUsages::ptrOperator(PtrOperatorAST *ast)
{
accept(ast);
}
const QList<LookupItem> results = typeofExpression(expression, scope,
TypeOfExpression::Preprocess);
void FindUsages::coreDeclarator(CoreDeclaratorAST *ast)
{
accept(ast);
}
reportResult(endToken, results);
void FindUsages::postfixDeclarator(PostfixDeclaratorAST *ast)
{
accept(ast);
}
bool FindUsages::visit(QualifiedNameAST *ast)
// AST
bool FindUsages::visit(ObjCSelectorArgumentAST *ast)
{
for (NestedNameSpecifierListAST *it = ast->nested_name_specifier_list; it; it = it->next) {
NestedNameSpecifierAST *nested_name_specifier = it->value;
(void) ast;
Q_ASSERT(!"unreachable");
return false;
}
if (NameAST *class_or_namespace_name = nested_name_specifier->class_or_namespace_name) {
SimpleNameAST *simple_name = class_or_namespace_name->asSimpleName();
void FindUsages::objCSelectorArgument(ObjCSelectorArgumentAST *ast)
{
if (! ast)
return;
TemplateIdAST *template_id = 0;
if (! simple_name) {
template_id = class_or_namespace_name->asTemplateId();
// unsigned name_token = ast->name_token;
// unsigned colon_token = ast->colon_token;
}
if (template_id) {
for (TemplateArgumentListAST *arg_it = template_id->template_argument_list; arg_it; arg_it = arg_it->next) {
accept(arg_it->value);
}
}
}
bool FindUsages::visit(AttributeAST *ast)
{
(void) ast;
Q_ASSERT(!"unreachable");
return false;
}
if (simple_name || template_id) {
const unsigned identifier_token = simple_name
? simple_name->identifier_token
: template_id->identifier_token;
void FindUsages::attribute(AttributeAST *ast)
{
if (! ast)
return;
if (identifier(identifier_token) == _id)
checkExpression(ast->firstToken(), identifier_token);
}
}
// unsigned identifier_token = ast->identifier_token;
// unsigned lparen_token = ast->lparen_token;
// unsigned tag_token = ast->tag_token;
for (ExpressionListAST *it = ast->expression_list; it; it = it->next) {
this->expression(it->value);
}
// unsigned rparen_token = ast->rparen_token;
}
if (NameAST *unqualified_name = ast->unqualified_name) {
unsigned identifier_token = 0;
if (SimpleNameAST *simple_name = unqualified_name->asSimpleName())
identifier_token = simple_name->identifier_token;
else if (DestructorNameAST *dtor_name = unqualified_name->asDestructorName())
identifier_token = dtor_name->identifier_token;
TemplateIdAST *template_id = 0;
if (! identifier_token) {
template_id = unqualified_name->asTemplateId();
if (template_id) {
identifier_token = template_id->identifier_token;
bool FindUsages::visit(DeclaratorAST *ast)
{
(void) ast;
Q_ASSERT(!"unreachable");
return false;
}
for (TemplateArgumentListAST *template_arguments = template_id->template_argument_list;
template_arguments; template_arguments = template_arguments->next) {
accept(template_arguments->value);
}
}
}
void FindUsages::declarator(DeclaratorAST *ast)
{
if (! ast)
return;
if (identifier_token && identifier(identifier_token) == _id)
checkExpression(ast->firstToken(), identifier_token);
for (SpecifierListAST *it = ast->attribute_list; it; it = it->next) {
this->specifier(it->value);
}
for (PtrOperatorListAST *it = ast->ptr_operator_list; it; it = it->next) {
this->ptrOperator(it->value);
}
this->coreDeclarator(ast->core_declarator);
for (PostfixDeclaratorListAST *it = ast->postfix_declarator_list; it; it = it->next) {
this->postfixDeclarator(it->value);
}
for (SpecifierListAST *it = ast->post_attribute_list; it; it = it->next) {
this->specifier(it->value);
}
// unsigned equals_token = ast->equals_token;
this->expression(ast->initializer);
}
bool FindUsages::visit(QtPropertyDeclarationItemAST *ast)
{
(void) ast;
Q_ASSERT(!"unreachable");
return false;
}
bool FindUsages::visit(EnumeratorAST *ast)
void FindUsages::qtPropertyDeclarationItem(QtPropertyDeclarationItemAST *ast)
{
const Identifier *id = identifier(ast->identifier_token);
if (id == _id) {
const QList<LookupItem> candidates = _context.lookup(control()->nameId(id), enclosingScope());
reportResult(ast->identifier_token, candidates);
}
if (! ast)
return;
accept(ast->expression);
// unsigned item_name_token = ast->item_name_token;
this->expression(ast->expression);
}
bool FindUsages::visit(QtInterfaceNameAST *ast)
{
(void) ast;
Q_ASSERT(!"unreachable");
return false;
}
bool FindUsages::visit(SimpleNameAST *ast)
void FindUsages::qtInterfaceName(QtInterfaceNameAST *ast)
{
const Identifier *id = identifier(ast->identifier_token);
if (id == _id) {
const QList<LookupItem> candidates = _context.lookup(ast->name, enclosingScope());
reportResult(ast->identifier_token, candidates);
if (! ast)
return;
/*const Name *interface_name =*/ this->name(ast->interface_name);
for (NameListAST *it = ast->constraint_list; it; it = it->next) {
/*const Name *value =*/ this->name(it->value);
}
}
bool FindUsages::visit(BaseSpecifierAST *ast)
{
(void) ast;
Q_ASSERT(!"unreachable");
return false;
}
bool FindUsages::visit(DestructorNameAST *ast)
void FindUsages::baseSpecifier(BaseSpecifierAST *ast)
{
const Identifier *id = identifier(ast->identifier_token);
if (id == _id) {
const QList<LookupItem> candidates = _context.lookup(ast->name, enclosingScope());
reportResult(ast->identifier_token, candidates);
}
if (! ast)
return;
// unsigned virtual_token = ast->virtual_token;
// unsigned access_specifier_token = ast->access_specifier_token;
/*const Name *name =*/ this->name(ast->name);
// BaseClass *symbol = ast->symbol;
}
bool FindUsages::visit(CtorInitializerAST *ast)
{
(void) ast;
Q_ASSERT(!"unreachable");
return false;
}
bool FindUsages::visit(TemplateIdAST *ast)
void FindUsages::ctorInitializer(CtorInitializerAST *ast)
{
if (_id == identifier(ast->identifier_token)) {
const QList<LookupItem> candidates = _context.lookup(ast->name, enclosingScope());
reportResult(ast->identifier_token, candidates);
}
if (! ast)
return;
for (TemplateArgumentListAST *template_arguments = ast->template_argument_list;
template_arguments; template_arguments = template_arguments->next) {
accept(template_arguments->value);
// unsigned colon_token = ast->colon_token;
for (MemInitializerListAST *it = ast->member_initializer_list; it; it = it->next) {
this->memInitializer(it->value);
}
// unsigned dot_dot_dot_token = ast->dot_dot_dot_token;
}
bool FindUsages::visit(EnumeratorAST *ast)
{
(void) ast;
Q_ASSERT(!"unreachable");
return false;
}
bool FindUsages::visit(ParameterDeclarationAST *ast)
void FindUsages::enumerator(EnumeratorAST *ast)
{
for (SpecifierListAST *it = ast->type_specifier_list; it; it = it->next)
accept(it->value);
if (DeclaratorAST *declarator = ast->declarator) {
for (SpecifierListAST *it = declarator->attribute_list; it; it = it->next)
accept(it->value);
for (PtrOperatorListAST *it = declarator->ptr_operator_list; it; it = it->next)
accept(it->value);
if (! ast)
return;
if (! _inSimpleDeclaration) // visit the core declarator only if we are not in simple-declaration.
accept(declarator->core_declarator);
// unsigned identifier_token = ast->identifier_token;
reportResult(ast->identifier_token, identifier(ast->identifier_token));
// unsigned equal_token = ast->equal_token;
this->expression(ast->expression);
}
for (PostfixDeclaratorListAST *it = declarator->postfix_declarator_list; it; it = it->next)
accept(it->value);
bool FindUsages::visit(ExceptionSpecificationAST *ast)
{
(void) ast;
Q_ASSERT(!"unreachable");
return false;
}
for (SpecifierListAST *it = declarator->post_attribute_list; it; it = it->next)
accept(it->value);
void FindUsages::exceptionSpecification(ExceptionSpecificationAST *ast)
{
if (! ast)
return;
accept(declarator->initializer);
// unsigned throw_token = ast->throw_token;
// unsigned lparen_token = ast->lparen_token;
// unsigned dot_dot_dot_token = ast->dot_dot_dot_token;
for (ExpressionListAST *it = ast->type_id_list; it; it = it->next) {
this->expression(it->value);
}
accept(ast->expression);
return false;
// unsigned rparen_token = ast->rparen_token;
}
bool FindUsages::visit(ExpressionOrDeclarationStatementAST *ast)
bool FindUsages::visit(MemInitializerAST *ast)
{
accept(ast->declaration);
(void) ast;
Q_ASSERT(!"unreachable");
return false;
}
bool FindUsages::visit(FunctionDeclaratorAST *ast)
void FindUsages::memInitializer(MemInitializerAST *ast)
{
accept(ast->parameters);
if (! ast)
return;
for (SpecifierListAST *it = ast->cv_qualifier_list; it; it = it->next)
accept(it->value);
if (_currentScope->isPrototypeScope()) {
Scope *classScope = _currentScope->enclosingClassScope();
if (! classScope) {
if (ClassOrNamespace *binding = _context.lookupType(_currentScope->owner())) {
foreach (Symbol *s, binding->symbols()) {
if (Class *k = s->asClass()) {
classScope = k->members();
break;
}
}
}
}
accept(ast->exception_specification);
if (classScope) {
Scope *previousScope = switchScope(classScope);
/*const Name *name =*/ this->name(ast->name);
(void) switchScope(previousScope);
}
}
// unsigned lparen_token = ast->lparen_token;
for (ExpressionListAST *it = ast->expression_list; it; it = it->next) {
this->expression(it->value);
}
// unsigned rparen_token = ast->rparen_token;
}
bool FindUsages::visit(NestedNameSpecifierAST *ast)
{
(void) ast;
Q_ASSERT(!"unreachable");
return false;
}
bool FindUsages::visit(SimpleDeclarationAST *ast)
void FindUsages::nestedNameSpecifier(NestedNameSpecifierAST *ast)
{
for (SpecifierListAST *it = ast->decl_specifier_list; it; it = it->next)
accept(it->value);
if (! ast)
return;
++_inSimpleDeclaration;
for (DeclaratorListAST *it = ast->declarator_list; it; it = it->next)
accept(it->value);
--_inSimpleDeclaration;
/*const Name *class_or_namespace_name =*/ this->name(ast->class_or_namespace_name);
// unsigned scope_token = ast->scope_token;
}
bool FindUsages::visit(NewPlacementAST *ast)
{
(void) ast;
Q_ASSERT(!"unreachable");
return false;
}
bool FindUsages::visit(ObjCSelectorAST *ast)
void FindUsages::newPlacement(NewPlacementAST *ast)
{
if (ast->name) {
const Identifier *id = ast->name->identifier();
if (id == _id) {
const QList<LookupItem> candidates = _context.lookup(ast->name, enclosingScope());
reportResult(ast->firstToken(), candidates);
}
if (! ast)
return;
// unsigned lparen_token = ast->lparen_token;
for (ExpressionListAST *it = ast->expression_list; it; it = it->next) {
this->expression(it->value);
}
// unsigned rparen_token = ast->rparen_token;
}
bool FindUsages::visit(NewArrayDeclaratorAST *ast)
{
(void) ast;
Q_ASSERT(!"unreachable");
return false;
}