diff options
Diffstat (limited to 'lib/interfaces/codemodel_utils.cpp')
-rw-r--r-- | lib/interfaces/codemodel_utils.cpp | 747 |
1 files changed, 747 insertions, 0 deletions
diff --git a/lib/interfaces/codemodel_utils.cpp b/lib/interfaces/codemodel_utils.cpp new file mode 100644 index 00000000..68211f34 --- /dev/null +++ b/lib/interfaces/codemodel_utils.cpp @@ -0,0 +1,747 @@ +/* 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., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, 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, QMap< 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, QMap< 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, QMap< 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, QMap< 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, QMap< 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, QMap< 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(); + QStringList l1 = dec->scope() + QStringList::split("::", dec->resultType() ); + QStringList l2 = QStringList::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 QStringList &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; +} + +QString 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 |