mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-25 19:32:54 +00:00
296 lines
8.5 KiB
C++
296 lines
8.5 KiB
C++
/* This file is part of KDevelop
|
|
Copyright 2002-2005 Roberto Raggi <roberto@kdevelop.org>
|
|
Copyright 2007 David Nolden <david.nolden.kdevelop@art-master.de>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License version 2 as published by the Free Software Foundation.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
//krazy:excludeall=cpp
|
|
|
|
#include "name_visitor.h"
|
|
#include "name_compiler.h"
|
|
#include "type_visitor.h"
|
|
#include "lexer.h"
|
|
#include "symbol.h"
|
|
#include "parsesession.h"
|
|
#include "tokens.h"
|
|
#include "expressionparser.h"
|
|
#include "expressionvisitor.h"
|
|
#include <language/duchain/duchainlock.h>
|
|
|
|
#include <QtCore/qdebug.h>
|
|
|
|
#define LOCKDUCHAIN DUChainReadLocker lock(DUChain::lock())
|
|
|
|
using namespace KDevelop;
|
|
using namespace Cpp;
|
|
|
|
NameASTVisitor::NameASTVisitor(ParseSession* session, Cpp::ExpressionVisitor* visitor, const KDevelop::DUContext* context, const KDevelop::TopDUContext* source, const KDevelop::DUContext* localVisibilityContext, const CursorInRevision& position, KDevelop::DUContext::SearchFlags localSearchFlags, bool debug )
|
|
: m_session(session), m_visitor(visitor), m_context(context), m_source(source), m_localContext(localVisibilityContext), m_find(m_context, m_source, localSearchFlags, CursorInRevision(position) ), m_debug(debug), m_finalName(0)
|
|
{
|
|
m_flags = localSearchFlags;
|
|
m_stopSearch = false;
|
|
}
|
|
|
|
void NameASTVisitor::visitUnqualifiedName(UnqualifiedNameAST *node)
|
|
{
|
|
if(m_stopSearch)
|
|
return;
|
|
IndexedString tmp_name;
|
|
|
|
if (node->id)
|
|
tmp_name = m_session->token_stream->symbol(node->id);
|
|
if (node->tilde)
|
|
tmp_name = IndexedString(QLatin1String("~") + tmp_name.str());
|
|
if (OperatorFunctionIdAST *op_id = node->operator_id) {
|
|
QString tmpString = QLatin1String("operator");
|
|
|
|
if (op_id->op && op_id->op->op)
|
|
tmpString += m_session->stringForNode(op_id->op, true);
|
|
else
|
|
tmpString += QLatin1String("{...cast...}");
|
|
|
|
tmp_name = IndexedString(tmpString);
|
|
|
|
m_typeSpecifier = op_id->type_specifier;
|
|
}
|
|
m_currentIdentifier = Identifier(tmp_name);
|
|
m_find.openIdentifier(m_currentIdentifier);
|
|
|
|
if (node->template_arguments) {
|
|
visitNodes(this, node->template_arguments);
|
|
} else if(node->end_token == node->start_token + 3 && node->id == node->start_token
|
|
&& m_session->token_stream->kind(node->id+1) == '<')
|
|
{
|
|
///@todo Represent this nicer in the AST
|
|
///It's probably a type-specifier with instantiation of the default-parameter, like "Bla<>".
|
|
m_find.openQualifiedIdentifier( ExpressionEvaluationResult() );
|
|
m_find.closeQualifiedIdentifier();
|
|
}
|
|
|
|
{
|
|
LOCKDUCHAIN;
|
|
m_find.closeIdentifier(node == m_finalName);
|
|
}
|
|
if( (node->id || node->operator_id) && !m_find.lastDeclarations().isEmpty() ) {
|
|
bool had = false;
|
|
uint start_token;
|
|
uint end_token;
|
|
if ( node->id ) {
|
|
start_token = node->id;
|
|
end_token = node->id + 1;
|
|
} else {
|
|
start_token = node->start_token;
|
|
end_token = node->end_token;
|
|
}
|
|
foreach(const DeclarationPointer &decl, m_find.lastDeclarations()) {
|
|
if(decl && !decl->isForwardDeclaration()) {
|
|
//Prefer registering non forward-declaration uses
|
|
if(m_visitor)
|
|
m_visitor->newUse( node, start_token, end_token, decl );
|
|
had = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!had) //only forward-declarations, register to any.
|
|
if(m_visitor)
|
|
m_visitor->newUse( node, start_token,end_token, m_find.lastDeclarations()[0] );
|
|
} else {
|
|
if(node == m_finalName) {
|
|
if(m_visitor) { //Create a zero use, which will be highlighted as an error
|
|
bool createUse = false;
|
|
{
|
|
LOCKDUCHAIN;
|
|
createUse = !m_foundSomething || !Cpp::isTemplateDependent(m_foundSomething.data());
|
|
}
|
|
if(createUse)
|
|
m_visitor->newUse(node, node->id, node->id+1, DeclarationPointer());
|
|
}
|
|
|
|
if( m_debug )
|
|
kDebug( 9007 ) << "failed to find " << m_currentIdentifier << " as part of " << m_session->stringForNode(node) << ", searched in " << m_find.describeLastContext();
|
|
}
|
|
}
|
|
|
|
_M_name.push(m_currentIdentifier);
|
|
|
|
if(!m_find.lastDeclarations().isEmpty()) {
|
|
m_foundSomething = m_find.lastDeclarations().first();
|
|
}
|
|
}
|
|
|
|
TypeSpecifierAST* NameASTVisitor::lastTypeSpecifier() const {
|
|
if(m_stopSearch)
|
|
return 0;
|
|
return m_typeSpecifier;
|
|
}
|
|
|
|
void NameASTVisitor::visitTemplateArgument(TemplateArgumentAST *node)
|
|
{
|
|
if(m_stopSearch)
|
|
return;
|
|
processTemplateArgument(node);
|
|
}
|
|
|
|
ExpressionEvaluationResult NameASTVisitor::processTemplateArgument(TemplateArgumentAST *node)
|
|
{
|
|
if(m_stopSearch)
|
|
return ExpressionEvaluationResult();
|
|
|
|
ExpressionEvaluationResult res;
|
|
bool opened = false;
|
|
if( node->expression ) {
|
|
bool ownVisitor = false;
|
|
if(!m_visitor) {
|
|
m_visitor = new ExpressionVisitor(m_session, m_source);
|
|
ownVisitor = true;
|
|
}
|
|
if (!node->expression->ducontext) {
|
|
node->expression->ducontext = const_cast<DUContext*>(m_localContext);
|
|
}
|
|
m_visitor->parse( node->expression );
|
|
|
|
if( m_visitor->lastType() ) {
|
|
LOCKDUCHAIN;
|
|
|
|
res.type = m_visitor->lastType()->indexed();
|
|
foreach(const DeclarationPointer &decl, m_visitor->lastDeclarations())
|
|
if(decl)
|
|
res.allDeclarationsList().append(decl->id());
|
|
|
|
res.isInstance = m_visitor->lastInstance().isInstance;
|
|
if(m_visitor->lastInstance().declaration)
|
|
res.instanceDeclaration = m_visitor->lastInstance().declaration->id();
|
|
|
|
m_find.openQualifiedIdentifier(res);
|
|
opened = true;
|
|
|
|
}else if( m_debug ) {
|
|
kDebug(9007) << "Failed to resolve template-argument " << m_session->stringForNode(node->expression);
|
|
}
|
|
|
|
if(ownVisitor) {
|
|
delete m_visitor;
|
|
m_visitor = 0;
|
|
}
|
|
|
|
} else if( node->type_id )
|
|
{
|
|
TypeASTVisitor v( m_session, m_visitor, m_localContext, m_source, m_localContext, m_debug );
|
|
v.run( node->type_id );
|
|
|
|
if(v.stoppedSearch()) {
|
|
m_stopSearch = true;
|
|
return ExpressionEvaluationResult();
|
|
}
|
|
|
|
res.type = v.type()->indexed();
|
|
|
|
if( res.type ) {
|
|
LOCKDUCHAIN;
|
|
foreach(const DeclarationPointer &decl, v.declarations())
|
|
if(decl)
|
|
res.allDeclarationsList().append(decl->id());
|
|
|
|
m_find.openQualifiedIdentifier(res);
|
|
opened = true;
|
|
}
|
|
|
|
}else{
|
|
LOCKDUCHAIN;
|
|
m_find.openQualifiedIdentifier(false);
|
|
m_find.openIdentifier(Identifier(m_session->stringForNode(node)));
|
|
m_find.closeIdentifier(false);
|
|
opened = true;
|
|
}
|
|
LOCKDUCHAIN;
|
|
if(opened)
|
|
m_find.closeQualifiedIdentifier();
|
|
|
|
m_currentIdentifier.appendTemplateIdentifier( typeIdentifierFromTemplateArgument(m_session, node) );
|
|
return res;
|
|
}
|
|
|
|
const QualifiedIdentifier& NameASTVisitor::identifier() const
|
|
{
|
|
if(m_stopSearch)
|
|
{
|
|
static const QualifiedIdentifier tmpQI;
|
|
return tmpQI;
|
|
}
|
|
return _M_name;
|
|
}
|
|
|
|
void NameASTVisitor::run(UnqualifiedNameAST *node, bool skipThisName)
|
|
{
|
|
m_finalName = node;
|
|
|
|
m_find.openQualifiedIdentifier(false);
|
|
m_typeSpecifier = 0;
|
|
_M_name.clear();
|
|
|
|
if(skipThisName)
|
|
DefaultVisitor::visitUnqualifiedName(node);
|
|
else
|
|
visit(node);
|
|
|
|
if(m_stopSearch)
|
|
return;
|
|
|
|
LOCKDUCHAIN;
|
|
m_find.closeQualifiedIdentifier();
|
|
|
|
if(m_find.lastDeclarations().isEmpty() && (m_flags & DUContext::NoUndefinedTemplateParams)) {
|
|
m_stopSearch = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
QList<KDevelop::DeclarationPointer> NameASTVisitor::declarations() const
|
|
{
|
|
if(m_stopSearch)
|
|
return QList<KDevelop::DeclarationPointer>();
|
|
return m_find.lastDeclarations();
|
|
}
|
|
|
|
|
|
void NameASTVisitor::run(NameAST *node, bool skipLastNamePart)
|
|
{
|
|
m_find.openQualifiedIdentifier(node->global);
|
|
m_typeSpecifier = 0;
|
|
|
|
_M_name.clear();
|
|
|
|
m_finalName = node->unqualified_name;
|
|
|
|
if(skipLastNamePart)
|
|
visitNodes(this, node->qualified_names); //Skip the unqualified name
|
|
else
|
|
visit(node);
|
|
|
|
if(m_stopSearch)
|
|
return;
|
|
|
|
_M_name.setExplicitlyGlobal( node->global );
|
|
LOCKDUCHAIN;
|
|
m_find.closeQualifiedIdentifier();
|
|
}
|
|
|
|
|
|
DeclarationPointer NameASTVisitor::foundSomething() const
|
|
{
|
|
return m_foundSomething;
|
|
}
|