You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdevelop/lib/interfaces/codemodel_utils.cpp

748 lines
21 KiB

/* This file is part of KDevelop
Copyright (C) 2003 Roberto Raggi <roberto@kdevelop.org>
Copyright (C) 2003 Alexander Dymo <adymo@kdevelop.org>
Copyright (C) 2004 Jonas Jacobi <j.jacobi@gmx.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
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.
*/
#include "codemodel_utils.h"
namespace CodeModelUtils
{
namespace Functions
{
void processClasses(FunctionList &list, const ClassDom dom)
{
const ClassList cllist = dom->classList();
for (ClassList::ConstIterator it = cllist.begin(); it != cllist.end(); ++it)
{
processClasses(list, *it);
}
const FunctionList fnlist = dom->functionList();
for (FunctionList::ConstIterator it = fnlist.begin(); it != fnlist.end(); ++it)
{
list.append(*it);
}
}
void processNamespaces(FunctionList &list, const NamespaceDom dom)
{
const NamespaceList nslist = dom->namespaceList();
for (NamespaceList::ConstIterator it = nslist.begin(); it != nslist.end(); ++it)
{
processNamespaces(list, *it);
}
const ClassList cllist = dom->classList();
for (ClassList::ConstIterator it = cllist.begin(); it != cllist.end(); ++it)
{
processClasses(list, *it);
}
const FunctionList fnlist = dom->functionList();
for (FunctionList::ConstIterator it = fnlist.begin(); it != fnlist.end(); ++it)
{
list.append(*it);
}
}
void processNamespaces( FunctionList & list, const NamespaceDom dom, TQMap< FunctionDom, Scope > & relations )
{
const NamespaceList nslist = dom->namespaceList();
for (NamespaceList::ConstIterator it = nslist.begin(); it != nslist.end(); ++it)
{
processNamespaces(list, *it, relations);
}
const ClassList cllist = dom->classList();
for (ClassList::ConstIterator it = cllist.begin(); it != cllist.end(); ++it)
{
processClasses(list, *it, relations, dom);
}
const FunctionList fnlist = dom->functionList();
for (FunctionList::ConstIterator it = fnlist.begin(); it != fnlist.end(); ++it)
{
list.append(*it);
relations[*it].ns = dom;
}
}
void processClasses( FunctionList & list, const ClassDom dom, TQMap< FunctionDom, Scope > & relations )
{
const ClassList cllist = dom->classList();
for (ClassList::ConstIterator it = cllist.begin(); it != cllist.end(); ++it)
{
processClasses(list, *it, relations);
}
const FunctionList fnlist = dom->functionList();
for (FunctionList::ConstIterator it = fnlist.begin(); it != fnlist.end(); ++it)
{
list.append(*it);
relations[*it].klass = dom;
}
}
void processClasses( FunctionList & list, const ClassDom dom, TQMap< FunctionDom, Scope > & relations, const NamespaceDom & nsdom )
{
const ClassList cllist = dom->classList();
for (ClassList::ConstIterator it = cllist.begin(); it != cllist.end(); ++it)
{
processClasses(list, *it, relations, nsdom);
}
const FunctionList fnlist = dom->functionList();
for (FunctionList::ConstIterator it = fnlist.begin(); it != fnlist.end(); ++it)
{
list.append(*it);
relations[*it].klass = dom;
relations[*it].ns = nsdom;
}
}
} // end of Functions namespace
namespace FunctionDefinitions
{
void processClasses(FunctionDefinitionList &list, const ClassDom dom)
{
const ClassList cllist = dom->classList();
for (ClassList::ConstIterator it = cllist.begin(); it != cllist.end(); ++it)
{
processClasses(list, *it);
}
const FunctionDefinitionList fnlist = dom->functionDefinitionList();
for (FunctionDefinitionList::ConstIterator it = fnlist.begin(); it != fnlist.end(); ++it)
{
list.append(*it);
}
}
void processNamespaces(FunctionDefinitionList &list, const NamespaceDom dom)
{
const NamespaceList nslist = dom->namespaceList();
for (NamespaceList::ConstIterator it = nslist.begin(); it != nslist.end(); ++it)
{
processNamespaces(list, *it);
}
const ClassList cllist = dom->classList();
for (ClassList::ConstIterator it = cllist.begin(); it != cllist.end(); ++it)
{
processClasses(list, *it);
}
const FunctionDefinitionList fnlist = dom->functionDefinitionList();
for (FunctionDefinitionList::ConstIterator it = fnlist.begin(); it != fnlist.end(); ++it)
{
list.append(*it);
}
}
void processNamespaces( FunctionDefinitionList & list, const NamespaceDom dom, TQMap< FunctionDefinitionDom, Scope > & relations )
{
const NamespaceList nslist = dom->namespaceList();
for (NamespaceList::ConstIterator it = nslist.begin(); it != nslist.end(); ++it)
{
processNamespaces(list, *it, relations);
}
const ClassList cllist = dom->classList();
for (ClassList::ConstIterator it = cllist.begin(); it != cllist.end(); ++it)
{
processClasses(list, *it, relations, dom);
}
const FunctionDefinitionList fnlist = dom->functionDefinitionList();
for (FunctionDefinitionList::ConstIterator it = fnlist.begin(); it != fnlist.end(); ++it)
{
list.append(*it);
relations[*it].ns = dom;
}
}
void processClasses( FunctionDefinitionList & list, const ClassDom dom, TQMap< FunctionDefinitionDom, Scope > & relations )
{
const ClassList cllist = dom->classList();
for (ClassList::ConstIterator it = cllist.begin(); it != cllist.end(); ++it)
{
processClasses(list, *it, relations);
}
const FunctionDefinitionList fnlist = dom->functionDefinitionList();
for (FunctionDefinitionList::ConstIterator it = fnlist.begin(); it != fnlist.end(); ++it)
{
list.append(*it);
relations[*it].klass = dom;
}
}
void processClasses( FunctionDefinitionList & list, const ClassDom dom, TQMap< FunctionDefinitionDom, Scope > & relations, const NamespaceDom & nsdom )
{
const ClassList cllist = dom->classList();
for (ClassList::ConstIterator it = cllist.begin(); it != cllist.end(); ++it)
{
processClasses(list, *it, relations, nsdom);
}
const FunctionDefinitionList fnlist = dom->functionDefinitionList();
for (FunctionDefinitionList::ConstIterator it = fnlist.begin(); it != fnlist.end(); ++it)
{
list.append(*it);
relations[*it].klass = dom;
relations[*it].ns = nsdom;
}
}
} // end of FunctionDefinitions namespace
FunctionList allFunctions(const FileDom &dom)
{
using namespace Functions;
FunctionList list;
const NamespaceList nslist = dom->namespaceList();
for (NamespaceList::ConstIterator it = nslist.begin(); it != nslist.end(); ++it)
{
processNamespaces(list, *it);
}
const ClassList cllist = dom->classList();
for (ClassList::ConstIterator it = cllist.begin(); it != cllist.end(); ++it)
{
processClasses(list, *it);
}
const FunctionList fnlist = dom->functionList();
for (FunctionList::ConstIterator it = fnlist.begin(); it != fnlist.end(); ++it)
{
list.append(*it);
}
return list;
}
AllFunctions allFunctionsDetailed( const FileDom & dom )
{
using namespace Functions;
AllFunctions list;
const NamespaceList nslist = dom->namespaceList();
for (NamespaceList::ConstIterator it = nslist.begin(); it != nslist.end(); ++it)
{
processNamespaces(list.functionList, *it, list.relations);
}
const ClassList cllist = dom->classList();
for (ClassList::ConstIterator it = cllist.begin(); it != cllist.end(); ++it)
{
processClasses(list.functionList, *it, list.relations);
}
const FunctionList fnlist = dom->functionList();
for (FunctionList::ConstIterator it = fnlist.begin(); it != fnlist.end(); ++it)
{
list.functionList.append(*it);
}
return list;
}
AllFunctionDefinitions allFunctionDefinitionsDetailed( const FileDom & dom )
{
using namespace FunctionDefinitions;
AllFunctionDefinitions list;
const NamespaceList nslist = dom->namespaceList();
for (NamespaceList::ConstIterator it = nslist.begin(); it != nslist.end(); ++it)
{
processNamespaces(list.functionList, *it, list.relations);
}
const ClassList cllist = dom->classList();
for (ClassList::ConstIterator it = cllist.begin(); it != cllist.end(); ++it)
{
processClasses(list.functionList, *it, list.relations);
}
const FunctionDefinitionList fnlist = dom->functionDefinitionList();
for (FunctionDefinitionList::ConstIterator it = fnlist.begin(); it != fnlist.end(); ++it)
{
list.functionList.append(*it);
}
return list;
}
bool resultTypesFit( const FunctionDom & dec, const FunctionDefinitionDom & def ) {
if( !def->resultType().contains("::") ) return dec->resultType() == def->resultType();
TQStringList l1 = dec->scope() + TQStringList::split("::", dec->resultType() );
TQStringList l2 = TQStringList::split("::", def->resultType() );
if( l1.isEmpty() || l2.isEmpty() || l1.back() != l2.back() ) return false;
while( !l1.isEmpty() && !l2.isEmpty() ) {
if( l1.back() == l2.back() ) {
l1.pop_back();
l2.pop_back();
} else {
l1.pop_back();
}
}
if( l2.isEmpty() ) return true;
return false;
}
bool compareDeclarationToDefinition( const FunctionDom & dec, const FunctionDefinitionDom & def )
{
if (dec->scope() == def->scope() && dec->name() == def->name() && resultTypesFit( dec, def ) && dec->isConstant() == def->isConstant())
{
const ArgumentList defList = def->argumentList(), decList = dec->argumentList();
if (defList.size() != decList.size())
return false;
size_t n = defList.size();
for(size_t i = 0; i < n; ++i)
if (defList[i]->type() != decList[i]->type())
return false;
return true;
}
return false;
}
bool compareDeclarationToDefinition( const FunctionDom & dec, const FunctionDefinitionDom & def, const std::set<NamespaceImportModel> & nsImports )
{
if (dec->name() == def->name() && resultTypesFit( dec, def ) && dec->isConstant() == def->isConstant())
{
const ArgumentList defList = def->argumentList(), decList = dec->argumentList();
if (defList.size() != decList.size())
return false;
size_t n = defList.size();
for(size_t i = 0; i < n; ++i)
if (defList[i]->type() != decList[i]->type())
return false;
const TQStringList &defScope = def->scope(), &decScope = dec->scope();
if (defScope != decScope)
{
if (defScope.size() >= decScope.size())
return false;
n = decScope.size();
for(size_t i1 = 0, i2 = 0; i1 < n; ++i1)
{
if (i2 >= defScope.size() || decScope[i1] != defScope[i2])
{
NamespaceImportModel model;
model.setName(decScope[i1]);
model.setFileName(def->fileName());
if (nsImports.find(model) == nsImports.end())
return false;
}
else
{
++i2;
}
}
}
return true;
}
return false;
}
FunctionList allFunctionsExhaustive(FileDom &dom) {
PredAmOwner<FunctionDom> ow( dom );
FunctionList ret;
findFunctionDeclarations( ow, dom->wholeGroup(), ret );
return ret;
}
FunctionDefinitionList allFunctionDefinitionsExhaustive(FileDom &dom) {
PredAmOwner<FunctionDefinitionDom> ow( dom );
FunctionDefinitionList ret;
findFunctionDefinitions( ow, dom->wholeGroup(), ret );
return ret;
}
ClassDom findClassByPosition( NamespaceModel* nameSpace, int line, int col )
{
if (nameSpace == 0)
return 0;
NamespaceList nsList = nameSpace->namespaceList();
for (NamespaceList::iterator i = nsList.begin(); i != nsList.end(); ++i)
{
ClassDom result = findClassByPosition(*i, line, col);
if (result != 0)
return result;
}
ClassList classes = nameSpace->classList();
for(ClassList::iterator i = classes.begin(); i != classes.end(); ++i)
{
ClassDom result = findClassByPosition( *i, line, col );
if (result != 0)
return result;
}
return 0;
}
ClassDom findClassByPosition( ClassModel* aClass, int line, int col )
{
if (aClass == 0)
return 0;
ClassList classes = aClass->classList();
for(ClassList::iterator i = classes.begin(); i != classes.end(); ++i)
{
ClassDom result = findClassByPosition( *i, line, col );
if (result != 0)
return result;
}
int startLine, startCol;
aClass->getStartPosition(&startLine, &startCol);
if (startLine <= line)
{
int endLine, endCol;
aClass->getEndPosition(&endLine, &endCol);
if (endLine >= line)
return (aClass);
}
return 0;
}
int findLastMethodLine( ClassDom aClass, CodeModelItem::Access access )
{
int point = -1;
const FunctionList functionList = aClass->functionList();
for( FunctionList::ConstIterator it=functionList.begin(); it!=functionList.end(); ++it )
{
int funEndLine, funEndColumn;
(*it)->getEndPosition( &funEndLine, &funEndColumn );
if ((*it)->access() == access && point < funEndLine)
point = funEndLine;
}
return point;
}
int findLastVariableLine( ClassDom aClass, CodeModelItem::Access access )
{
int point = -1;
const VariableList varList = aClass->variableList();
for( VariableList::ConstIterator it= varList.begin(); it!= varList.end(); ++it )
{
int varEndLine, varEndColumn;
(*it)->getEndPosition( &varEndLine, &varEndColumn );
if ((*it)->access() == access && point < varEndLine)
point = varEndLine;
}
return point;
}
TQString accessSpecifierToString( CodeModelItem::Access access )
{
switch(access)
{
case CodeModelItem::Public: return "public";
case CodeModelItem::Protected: return "protected";
case CodeModelItem::Private: return "private";
default: return "unknown";
}
}
FunctionDefinitionDom CodeModelHelper::functionDefinitionAt(NamespaceDom ns, int line, int column)
{
NamespaceList namespaceList = ns->namespaceList();
NamespaceList::iterator nslEnd = namespaceList.end();
for (NamespaceList::iterator it=namespaceList.begin(); it!=nslEnd; ++it)
{
if (FunctionDefinitionDom def = functionDefinitionAt(*it, line, column))
return def;
}
ClassList classList = ns->classList();
ClassList::iterator clEnd = classList.end();
for (ClassList::iterator it=classList.begin(); it!=clEnd; ++it)
{
if (FunctionDefinitionDom def = functionDefinitionAt(*it, line, column))
return def;
}
FunctionDefinitionList functionDefinitionList = ns->functionDefinitionList();
FunctionDefinitionList::iterator fdlEnd = functionDefinitionList.end();
for (FunctionDefinitionList::iterator it=functionDefinitionList.begin();
it!=fdlEnd; ++it )
{
if (FunctionDefinitionDom def = functionDefinitionAt(*it, line, column))
return def;
}
return FunctionDefinitionDom();
}
FunctionDefinitionDom CodeModelHelper::functionDefinitionAt(ClassDom klass, int line, int column)
{
ClassList classList = klass->classList();
ClassList::iterator clEnd = classList.end();
for (ClassList::iterator it=classList.begin(); it!=clEnd; ++it)
{
if (FunctionDefinitionDom def = functionDefinitionAt(*it, line, column))
return def;
}
FunctionDefinitionList functionDefinitionList = klass->functionDefinitionList();
FunctionDefinitionList::iterator fdlEnd = functionDefinitionList.end();
for (FunctionDefinitionList::Iterator it=functionDefinitionList.begin();
it!=fdlEnd; ++it)
{
if (FunctionDefinitionDom def = functionDefinitionAt(*it, line, column))
return def;
}
return FunctionDefinitionDom();
}
FunctionDefinitionDom CodeModelHelper::functionDefinitionAt(FunctionDefinitionDom fun, int line, int // column
)
{
int startLine, startColumn;
int endLine, endColumn;
fun->getStartPosition(&startLine, &startColumn);
fun->getEndPosition(&endLine, &endColumn);
if (!(line >= startLine && line <= endLine) || fun->fileName() != m_fileName )
return FunctionDefinitionDom();
/*
if (line == startLine && column < startColumn)
return FunctionDefinitionDom();
if (line == endLine && column > endColumn)
return FunctionDefinitionDom();*/
return fun;
}
FunctionDom CodeModelHelper::functionDeclarationAt(NamespaceDom ns, int line, int column)
{
NamespaceList namespaceList = ns->namespaceList();
NamespaceList::iterator nsEnd = namespaceList.end();
for (NamespaceList::iterator it=namespaceList.begin(); it!=nsEnd; ++it)
{
if (FunctionDom def = functionDeclarationAt(*it, line, column))
return def;
}
ClassList classList = ns->classList();
ClassList::iterator clEnd = classList.end();
for (ClassList::iterator it=classList.begin(); it!=clEnd; ++it)
{
if (FunctionDom def = functionDeclarationAt(*it, line, column))
return def;
}
FunctionList functionList = ns->functionList();
FunctionList::iterator flEnd = functionList.end();
for (FunctionList::iterator it=functionList.begin();
it!=flEnd; ++it )
{
if (FunctionDom def = functionDeclarationAt(*it, line, column))
return def;
}
return FunctionDom();
}
FunctionDom CodeModelHelper::functionDeclarationAt(ClassDom klass, int line, int column)
{
ClassList classList = klass->classList();
ClassList::iterator clEnd = classList.end();
for (ClassList::iterator it=classList.begin(); it!=clEnd; ++it)
{
if (FunctionDom def = functionDeclarationAt(*it, line, column))
return def;
}
FunctionList functionList = klass->functionList();
FunctionList::iterator flEnd = functionList.end();
for (FunctionList::Iterator it=functionList.begin();
it!=flEnd; ++it)
{
if (FunctionDom def = functionDeclarationAt(*it, line, column))
return def;
}
return FunctionDom();
}
FunctionDom CodeModelHelper::functionDeclarationAt(FunctionDom fun, int line, int // column
)
{
int startLine, startColumn;
int endLine, endColumn;
fun->getStartPosition(&startLine, &startColumn);
fun->getEndPosition(&endLine, &endColumn);
if (!(line >= startLine && line <= endLine) || fun->fileName() != m_fileName )
return FunctionDom();
/* if (line == startLine && column < startColumn)
return FunctionDom();
if (line == endLine && column > endColumn)
return FunctionDom();*/
return fun;
}
ClassDom CodeModelHelper::classAt(NamespaceDom ns, int line, int column)
{
NamespaceList namespaceList = ns->namespaceList();
NamespaceList::iterator nsEnd = namespaceList.end();
for (NamespaceList::iterator it=namespaceList.begin(); it!=nsEnd; ++it)
{
if (ClassDom def = classAt(*it, line, column))
return def;
}
ClassList classList = ns->classList();
ClassList::iterator clEnd = classList.end();
for (ClassList::iterator it=classList.begin(); it!=clEnd; ++it)
{
if (ClassDom def = classAt(*it, line, column))
return def;
}
return ClassDom();
}
ClassDom CodeModelHelper::classAt(ClassDom klass, int line, int column)
{
ClassList classList = klass->classList();
ClassList::iterator clEnd = classList.end();
for (ClassList::iterator it=classList.begin(); it!=clEnd; ++it)
{
if (ClassDom def = classAt(*it, line, column))
return def;
}
int startLine, startColumn;
int endLine, endColumn;
klass->getStartPosition(&startLine, &startColumn);
klass->getEndPosition(&endLine, &endColumn);
if (!(line >= startLine && line <= endLine) || klass->fileName() != m_fileName )
return ClassDom();
return klass;
}
CodeModelHelper::CodeModelHelper( CodeModel* model, FileDom file ) : m_model( model ) {
if( !file ) return;
m_files = file->wholeGroup();
m_fileName = file->name();
}
FunctionDom CodeModelHelper::functionAt( int line, int column, FunctionTypes types ) {
if( m_files.isEmpty() ) return FunctionDom();
FunctionDom ret;
FileList::iterator it = m_files.begin();
while( it != m_files.end() ) {
if( types & Declaration ) {
ret = functionDeclarationAt(model_cast<NamespaceDom>(*it), line, column);
if(ret) return ret;
}
if( types & Definition ) {
FunctionDefinitionDom r = functionDefinitionAt(model_cast<NamespaceDom>(*it), line, column);
if(r) {
ret = model_cast<FunctionDom>( r );
return ret;
}
}
++it;
}
return ret;
}
ClassDom CodeModelHelper::classAt( int line, int column ) {
if( m_files.isEmpty() ) return ClassDom();
ClassDom ret;
FileList::iterator it = m_files.begin();
while( it != m_files.end() ) {
ret = classAt( model_cast<NamespaceDom>(*it), line, column );
if(ret) return ret;
++it;
}
return ret;
}
}//end of namespace CodeModeUtils