diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f0348b..ac80178 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,71 +1,57 @@ project(java) -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.10) -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${java_SOURCE_DIR}/cmake) +find_package (ECM 5.28.0 REQUIRED CONFIG) +set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH}) -find_package(KDE4 REQUIRED) -include (KDE4Defaults) -include (MacroLibrary) -include (MacroOptionalAddSubdirectory) +include(KDEInstallDirs) +include(KDECMakeSettings) +include(GenerateExportHeader) -find_package(KDevPlatform REQUIRED) +find_package(KF5 REQUIRED COMPONENTS Archive) +find_package(KDevPlatform REQUIRED) find_package(KDevelop-PG-Qt REQUIRED) include_directories(${KDEVPGQT_INCLUDE_DIR}) if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "Intel") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") endif() add_subdirectory(parser) add_subdirectory(settings) add_subdirectory(duchain) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} - ${KDE4_INCLUDES} - ${KDE4_INCLUDE_DIR}/threadweaver - ${KDE4_INCLUDE_DIR}/kdevelop-pg-qt - ${CMAKE_CURRENT_SOURCE_DIR}/parser - ${CMAKE_CURRENT_BINARY_DIR}/parser - ${KDEVPLATFORM_INCLUDE_DIR} ) ########### next target ############### -add_definitions( ${QT_DEFINITIONS} ${KDE4_DEFINITIONS} -DKDE_DEFAULT_DEBUG_AREA=9013 ) - set(kdevjavalanguagesupport_PART_SRCS javalanguagesupport.cpp parsejob.cpp completion/worker.cpp completion/items.cpp completion/context.cpp completion/model.cpp completion/helpers.cpp + + $ +) + +kdevplatform_add_plugin(kdevjavalanguagesupport JSON kdevjavasupport.json SOURCES + ${kdevjavalanguagesupport_PART_SRCS} ) -kde4_add_plugin(kdevjavalanguagesupport ${kdevjavalanguagesupport_PART_SRCS}) target_link_libraries(kdevjavalanguagesupport - ${KDE4_KTEXTEDITOR_LIBS} - ${KDEVPLATFORM_INTERFACES_LIBRARIES} - ${KDEVPLATFORM_PROJECT_LIBRARIES} - ${KDE4_THREADWEAVER_LIBRARIES} - ${KDEVPLATFORM_LANGUAGE_LIBRARIES} - ${KDE4_KDEUI_LIBS} + KF5::ThreadWeaver + KF5::Archive kdev4javaparser kdevjavaduchain ) - -install(TARGETS kdevjavalanguagesupport DESTINATION ${PLUGIN_INSTALL_DIR}) - - -########### install files ############### - -configure_file(kdevjavasupport.desktop.cmake ${CMAKE_CURRENT_BINARY_DIR}/kdevjavasupport.desktop) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kdevjavasupport.desktop DESTINATION ${SERVICES_INSTALL_DIR}) diff --git a/cmake/FindKDevPlatform.cmake b/cmake/FindKDevPlatform.cmake deleted file mode 100644 index 1a771c5..0000000 --- a/cmake/FindKDevPlatform.cmake +++ /dev/null @@ -1,46 +0,0 @@ -# -# Find the KDevelop Platform modules and sets various variables accordingly -# -# Example usage of this module: -# find_package(KDevPlatform 1.0.0 REQUIRED) -# -# The version number and REQUIRED flag are optional. You can set CMAKE_PREFIX_PATH -# variable to help it find the required files and directories - -# KDEVPLATFORM_FOUND - set to TRUE if the platform was found and the version is compatible FALSE otherwise -# -# KDEVPLATFORM_VERSION - The version number of kdevplatform -# KDEVPLATFORM_VERSION_MAJOR - The major version number of kdevplatform -# KDEVPLATFORM_VERSION_MINOR - The minor version number of kdevplatform -# KDEVPLATFORM_VERSION_PATCH - The patch version number of kdevplatform -# KDEVPLATFORM_INCLUDE_DIR - include dir of the platform, for example /usr/include/kdevplatform -# KDEVPLATFORM_INTERFACES_LIBRARIES - interfaces module library -# KDEVPLATFORM_LANGUAGE_LIBRARIES - language module library -# KDEVPLATFORM_OUTPUTVIEW_LIBRARIES - outputview module library -# KDEVPLATFORM_PROJECT_LIBRARIES - project module library -# KDEVPLATFORM_SUBLIME_LIBRARIES - sublime module library -# KDEVPLATFORM_SHELL_LIBRARIES - shell module library -# KDEVPLATFORM_TESTS_LIBRARIES - library to write tests for plugins, -# contains some useful tools and a way to replace parts of Core -# classes with custom implementations -# KDEVPLATFORM_UTIL_LIBRARIES - util module library -# KDEVPLATFORM_VCS_LIBRARIES - vcs module library -# KDEVPLATFORM_SOURCEFORMATTER_LIBRARIES - source formatter library -# KDEVPLATFORM_DEBUGGER_LIBRARIES - debugger module library -# -# The following macros are added (from KDevPlatformMacros.cmake): -# -# KDEVPLATFORM_ADD_APP_TEMPLATES( template1 ... templateN ) -# Use this to get packaged template archives for the given templates. -# Parameters should be the directories containing the templates. -# -# Copyright 2007 Andreas Pakulat -# Redistribution and use is allowed according to the terms of the BSD license. - -set(_KDevPlatform_FIND_QUIETLY ${KDevPlatform_FIND_QUIETLY}) -find_package( KDevPlatform ${KDevPlatform_FIND_VERSION} NO_MODULE ) -set(KDevPlatform_FIND_QUIETLY ${_KDevPlatform_FIND_QUIETLY}) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(KDevPlatform DEFAULT_MSG KDevPlatform_CONFIG ) - diff --git a/completion/context.cpp b/completion/context.cpp index 45ec174..66654fd 100644 --- a/completion/context.cpp +++ b/completion/context.cpp @@ -1,358 +1,358 @@ /* Copyright 2007 David Nolden Copyright 2008 Hamish Rodda 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. */ #include "context.h" #include #include #include #include #include #include #include #include #include #include #include "javalanguagesupport.h" #include #include "../duchain/helpers.h" #define LOCKDUCHAIN DUChainReadLocker lock(DUChain::lock()) #define ifDebug(x) x //Whether the list of argument-hints should contain all overloaded versions of operators. //Disabled for now, because there is usually a huge list of overloaded operators. const int maxOverloadedOperatorArgumentHints = 5; const int maxOverloadedArgumentHints = 5; using namespace KDevelop; namespace java { ///@todo move these together with those from expressionvisitor into an own file, or make them unnecessary QList convert( const QList& list ) { QList ret; foreach( Declaration* decl, list ) ret << DeclarationPointer(decl); return ret; } QList convert( const QList& list ) { QList ret; foreach( DeclarationPointer decl, list ) if( decl ) ret << decl.data(); return ret; } ///Extracts the last line from the given string QString extractLastLine(const QString& str) { int prevLineEnd = str.lastIndexOf('\n'); if(prevLineEnd != -1) return str.mid(prevLineEnd+1); else return str; } int completionRecursionDepth = 0; CodeCompletionContext::CodeCompletionContext(DUContextPointer context, const QString& text, const QString& followingText, const KDevelop::CursorInRevision& position, int depth, const QStringList& knownArgumentExpressions, int line) : KDevelop::CodeCompletionContext(context, text, position, depth) - , m_memberAccessOperation(NoMemberAccess), m_followingText( followingText ), + , m_memberAccessOperation(NoMemberAccess), m_followingText( followingText ), m_knownArgumentExpressions( knownArgumentExpressions) { #warning What to do with knownArgumentExpressions ? m_valid = isValidPosition(); if( !m_valid ) { - kDebug() << "position not valid for code-completion" ; + qDebug() << "position not valid for code-completion" ; return; } - ifDebug( kDebug() << "non-processed text: " << m_text; ) + ifDebug( qDebug() << "non-processed text: " << m_text; ) // m_text = Utils::clearComments( m_text ); // m_text = Utils::clearStrings( m_text ); // m_text = Utils::stripFinalWhitespace( m_text ); - ifDebug( kDebug() << "processed text: " << m_text; ) + ifDebug( qDebug() << "processed text: " << m_text; ) ///@todo template-parameters ///First: find out what kind of completion we are dealing with if (m_text.endsWith( ';' ) || m_text.endsWith('}') || m_text.endsWith('{') || m_text.endsWith(')') ) { ///We're at the beginning of a new statement. General completion is valid. return; } if( m_text.endsWith('.') ) { setMemberAccessOperation(MemberAccess); m_text = m_text.left( m_text.length()-1 ); } ///Now find out where the expression starts /** * Possible cases: * a = exp; - partially handled * ... * return exp; * emit exp; * throw exp; * new Class; * a=function(exp * a = exp( * ClassType instance( * * What else? * * When the left and right part are only separated by a whitespace, * expressionAt returns both sides * */ - + } CodeCompletionContext::~CodeCompletionContext() { } bool CodeCompletionContext::isValidPosition() const { // TODO return true; } CodeCompletionContext* CodeCompletionContext::parentContext() { return static_cast(KDevelop::CodeCompletionContext::parentContext()); } QList CodeCompletionContext::completionItems(bool& abort, bool fullCompletion) { LOCKDUCHAIN; QList items; if (!m_duContext || !m_valid) return items; typedef QPair DeclarationDepthPair; if(!m_storedItems.isEmpty()) { items = m_storedItems; } else { standardAccessCompletionItems(items); - kDebug() << "Found declarations:" << items.count(); + qDebug() << "Found declarations:" << items.count(); } return items; } void CodeCompletionContext::standardAccessCompletionItems(QList< CompletionTreeItemPointer >& items) { //Normal case: Show all visible declarations typedef QPair DeclarationDepthPair; QSet hadNamespaceDeclarations; bool typeIsConst = false; /*if (Declaration* func = Cpp::localFunctionFromCodeContext(m_duContext.data())) { if (func->abstractType() && (func->abstractType()->modifiers() & AbstractType::ConstModifier)) typeIsConst = true; }*/ - QList decls = m_duContext->allDeclarations(m_duContext->type() == DUContext::Class ? m_duContext->range().end : m_position, m_duContext->topContext()); + QVector decls = m_duContext->allDeclarations(m_duContext->type() == DUContext::Class ? m_duContext->range().end : m_position, m_duContext->topContext()); QList moreDecls; Q_ASSERT(m_duContext); if(m_duContext) { //Collect the Declarations from all "using namespace" imported contexts TopDUContext* top = m_duContext->topContext(); QSet packages; // Determine which identifiers to search for // Non-static imports foreach (Declaration* import, top->findLocalDeclarations(globalImportIdentifier())) if (NamespaceAliasDeclaration* alias = dynamic_cast(import)) if (alias->importIdentifier().last() == Identifier("*")) packages.insert( alias->importIdentifier().left(-1) ); else moreDecls << top->findDeclarations(alias->importIdentifier()); // Static imports foreach (Declaration* import, top->findLocalDeclarations(KDevelop::Identifier(globalStaticImportIdentifier))) if (NamespaceAliasDeclaration* alias = dynamic_cast(import)) if (alias->importIdentifier().last() == Identifier("*")) // TODO static-filter packages.insert( alias->importIdentifier().left(-1) ); else // TODO static-filter moreDecls << top->findDeclarations(alias->importIdentifier()); - kDebug() << "Found imported packages to retrieve declarations from:"; + qDebug() << "Found imported packages to retrieve declarations from:"; foreach(const QualifiedIdentifier &package, packages) { QList importedContextDecls = m_duContext->findDeclarations( package ); - kDebug() << package.toStringList().join(".") << "context declarations found: " << importedContextDecls.count(); + qDebug() << package.toStringList().join(".") << "context declarations found: " << importedContextDecls.count(); foreach(Declaration* contextDecl, importedContextDecls) { if(contextDecl->kind() != Declaration::Namespace || !contextDecl->internalContext()) continue; DUContext* context = contextDecl->internalContext(); /*if(context->range().contains(m_duContext->range())) { - kDebug() << "Ignoring same context " << context << m_duContext; + qDebug() << "Ignoring same context " << context << m_duContext; continue; //If the context surrounds the current one, the declarations are visible through allDeclarations(..). }*/ foreach(Declaration* decl, context->localDeclarations()) if(filterDeclaration(decl)) { - kDebug() << "Adding declaration" << decl << decl->toString(); + qDebug() << "Adding declaration" << decl << decl->toString(); moreDecls << decl; } else { - kDebug() << "Filtered out declaration" << decl; + qDebug() << "Filtered out declaration" << decl; } } } } /*QList oldDecls = decls; decls.clear(); //Remove pure function-definitions before doing overload-resolution, so they don't hide their own declarations. foreach( const DeclarationDepthPair& decl, oldDecls ) if(!dynamic_cast(decl.first) || !static_cast(decl.first)->hasDeclaration()) { if(decl.first->kind() == Declaration::Namespace) { QualifiedIdentifier id = decl.first->qualifiedIdentifier(); if(hadNamespaceDeclarations.contains(id)) continue; hadNamespaceDeclarations.insert(id); } if(filterDeclaration(decl.first, 0, true, typeIsConst)) { decls << decl; } } decls = Cpp::hideOverloadedDeclarations(decls);*/ foreach( const DeclarationDepthPair& decl, decls ) if(filterDeclaration(decl.first)) items << CompletionTreeItemPointer( new NormalDeclarationCompletionItem(DeclarationPointer(decl.first), KDevelop::CodeCompletionContext::Ptr(this), decl.second ) ); foreach( Declaration* decl, moreDecls ) items << CompletionTreeItemPointer( new NormalDeclarationCompletionItem(DeclarationPointer(decl), KDevelop::CodeCompletionContext::Ptr(this), 1200 ) ); #if 0 ///Eventually show additional specificly known items for the matched argument-type, like for example enumerators for enum types CodeCompletionContext* parent = parentContext(); if(parent) { if(parent->memberAccessOperation() == FunctionCallAccess) { foreach(const Cpp::OverloadResolutionFunction& function, parent->functions()) { if(function.function.isValid() && function.function.isViable() && function.function.declaration()) { //uint parameterNumber = parent->m_knownArgumentExpressions.size() + function.matchedArguments; Declaration* functionDecl = function.function.declaration().data(); if(functionDecl->type()->arguments().count() > function.matchedArguments) { items += specialItemsForArgumentType(functionDecl->type()->arguments()[function.matchedArguments]); } } } } } ///Eventually add a "this" item DUContext* functionContext = m_duContext.data(); if(!m_onlyShowSignals && !m_onlyShowSlots && !m_onlyShowTypes) { while(functionContext && functionContext->type() == DUContext::Other && functionContext->parentContext()->type() == DUContext::Other) functionContext = functionContext->parentContext(); } ClassFunctionDeclaration* classFun = dynamic_cast(DUChainUtils::declarationForDefinition(functionContext->owner(), m_duContext->topContext())); if(classFun && !classFun->isStatic() && classFun->context()->owner() && !m_onlyShowSignals && !m_onlyShowSlots && !m_onlyShowTypes) { AbstractType::Ptr classType = classFun->context()->owner()->abstractType(); if(classFun->abstractType()->modifiers() & AbstractType::ConstModifier) classType->setModifiers((AbstractType::CommonModifiers)(classType->modifiers() | AbstractType::ConstModifier)); PointerType::Ptr thisPointer(new PointerType()); thisPointer->setModifiers(AbstractType::ConstModifier); thisPointer->setBaseType(classType); - KSharedPtr item( new TypeConversionCompletionItem("this", thisPointer->indexed(), 0, KSharedPtr (this)) ); + QExplicitlySharedDataPointer item( new TypeConversionCompletionItem("this", thisPointer->indexed(), 0, QExplicitlySharedDataPointer (this)) ); item->setPrefix(thisPointer->toString()); QList lst; lst += CompletionTreeItemPointer(item.data()); eventuallyAddGroup(i18n("C++ Builtin"), 800, lst); } //Eventually add missing include-completion in cases like NotIncludedClass| // if(!m_followingText.trimmed().isEmpty()) { // uint oldItemCount = items.count(); // items += missingIncludeCompletionItems(totalExpression, m_followingText.trimmed() + ": ", ExpressionEvaluationResult(), m_duContext.data(), 0); #ifndef TEST_COMPLETION MissingIncludeCompletionModel::self().startWithExpression(m_duContext, QString(), m_followingText.trimmed()); #endif -// kDebug() << QString("added %1 missing-includes for %2").arg(items.count()-oldItemCount).arg(totalExpression); +// qDebug() << QString("added %1 missing-includes for %2").arg(items.count()-oldItemCount).arg(totalExpression); // } eventuallyAddGroup(i18n("C++ Builtin"), 800, keywordCompletionItems()); #endif } bool CodeCompletionContext::filterDeclaration(KDevelop::Declaration* decl, KDevelop::DUContext* declarationContext, bool dynamic, bool typeIsConst) { if(!decl) return false; if (dynamic_cast(decl)) return false; - if (decl->kind() == DUContext::Namespace) + if (decl->kind() == Declaration::Kind::Namespace) return false; - + //if(m_onlyShowTypes && decl->kind() != Declaration::Type && decl->kind() != Declaration::Namespace) //return false; /*if(m_onlyShowSignals || m_onlyShowSlots) { Cpp::QtFunctionDeclaration* qtFunction = dynamic_cast(decl); if(!qtFunction || (m_onlyShowSignals && !qtFunction->isSignal()) || (m_onlyShowSlots && !qtFunction->isSlot())) return false; }*/ /*if(dynamic && decl->context()->type() == DUContext::Class) { ClassMemberDeclaration* classMember = dynamic_cast(decl); if(classMember) return filterDeclaration(classMember, declarationContext, typeIsConst); }*/ return true; } int CodeCompletionContext::memberAccessOperation() const { return m_memberAccessOperation; } void CodeCompletionContext::setMemberAccessOperation(int operation) { m_memberAccessOperation = operation; } } diff --git a/completion/context.h b/completion/context.h index 80135cb..f558acf 100644 --- a/completion/context.h +++ b/completion/context.h @@ -1,105 +1,104 @@ /* Copyright 2007 David Nolden Copyright 2008 Hamish Rodda 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. */ #ifndef CODECOMPLETIONCONTEXT_H #define CODECOMPLETIONCONTEXT_H #include -#include +#include #include -#include #include "items.h" namespace KTextEditor { class View; class Cursor; } namespace KDevelop { class DUContext; class AbstractType; class CompletionTreeItem; - typedef KSharedPtr CompletionTreeItemPointer; + using CompletionTreeItemPointer = QExplicitlySharedDataPointer; } namespace java { /** * This class is responsible for finding out what kind of completion is needed, what expression should be evaluated for the container-class of the completion, what conversion will be applied to the result of the completion, etc. * */ class CodeCompletionContext : public KDevelop::CodeCompletionContext { public: - typedef KSharedPtr Ptr; + typedef QExplicitlySharedDataPointer Ptr; /** * @param firstContext should be true for a context that has no parent. Such a context will never be a function-call context. * @param text the text to analyze. It usually is the text in the range starting at the beginning of the context, and ending at the position where completion should start * @warning The du-chain must be unlocked when this is called * */ CodeCompletionContext(KDevelop::DUContextPointer context, const QString& text, const QString &followingText, const KDevelop::CursorInRevision& cursor, int depth = 0, const QStringList &knownArgumentExpressions = QStringList(), int line = -1); ~CodeCompletionContext(); ///Computes the full set of completion items, using the information retrieved earlier. ///Should only be called on the first context, parent contexts are included in the computations. ///@param Abort is checked regularly, and if it is false, the computation is aborted. virtual QList completionItems(bool& abort, bool fullCompletion = true); void standardAccessCompletionItems(/*const KDevelop::CursorInRevision& position,*/ QList& items); - + bool isValidPosition() const; /** * When memberAccessOperation is FunctionCallAccess, * this returns all functions available for matching, together with the argument-number that should be matched. * */ const QList& functions() const; virtual CodeCompletionContext* parentContext(); bool filterDeclaration(KDevelop::Declaration* decl, KDevelop::DUContext* declarationContext = 0, bool dynamic = false, bool typeIsConst = false); enum MemberAccessOperation { NoMemberAccess, ///With NoMemberAccess, a global completion should be done MemberAccess, ///klass. ArrowMemberAccess, ///klass-> StaticMemberChoose, /// Class:: MemberChoose, /// klass->ParentClass:: FunctionCallAccess, ///"function(". Will never appear as initial access-operation, but as parentContext() access-operation. TemplateAccess, ///bla<. Will never appear as initial access-operation, but as parentContext() access-operation. SignalAccess, ///All signals from MemberAccessContainer should be listed SlotAccess, ///All slots from MemberAccessContainer should be listed IncludeListAccess, ///A list of include-files should be presented. Get the list through includeItems() ReturnAccess, DeleteAccess /// Any item which can be deleted or provide deletable results should be listed }; int memberAccessOperation() const; void setMemberAccessOperation(int operation); private: QList m_storedItems; int m_memberAccessOperation; QString m_followingText; QStringList m_knownArgumentExpressions; }; } #endif diff --git a/completion/helpers.cpp b/completion/helpers.cpp index c695dcc..debf2c0 100644 --- a/completion/helpers.cpp +++ b/completion/helpers.cpp @@ -1,225 +1,225 @@ /* * KDevelop Java Code Completion Support * * Copyright 2007-2008 David Nolden * Copyright 2008 Hamish Rodda * * This program 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 program 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "helpers.h" #include #include #include #include #include #include #include #include #include #include "items.h" using namespace KDevelop; namespace java { QString createArgumentList(const NormalDeclarationCompletionItem& item, QList* highlighting, bool includeDefaultParams, bool noShortening ) { QString ret; - + Declaration* dec(item.declaration().data()); if (!dec) { - kDebug() << "No declaration for item"; + qDebug() << "No declaration for item"; return ret; } TopDUContext* top = 0; if(item.completionContext() && item.completionContext()->duContext()) top = item.completionContext()->duContext()->topContext(); //if( item.completionContext() && item.completionContext()->memberAccessOperation() == CodeCompletionContext::FunctionCallAccess && item.completionContext()->functions().count() > item.listOffset ) //f = item.completionContext()->functions()[item.listOffset]; QTextFormat normalFormat(QTextFormat::CharFormat); QTextFormat highlightFormat; //highlightFormat is invalid, so kate uses the match-quality dependent color. QTextCharFormat boldFormat; boldFormat.setFontWeight(QFont::Bold); AbstractFunctionDeclaration* decl = dynamic_cast(dec); if (!decl) { - kDebug() << "Declaration is not a subclass of AbstractFunctionDeclaration" << dec->toString(); + qDebug() << "Declaration is not a subclass of AbstractFunctionDeclaration" << dec->toString(); } - + FunctionType::Ptr functionType = dec->type(); if (!functionType) { - kDebug() << "Type is not a function type" << dec->abstractType()->toString(); + qDebug() << "Type is not a function type" << dec->abstractType()->toString(); } - + if (functionType && decl) { QVector parameters; - if( DUChainUtils::getArgumentContext(dec) ) - parameters = DUChainUtils::getArgumentContext(dec)->localDeclarations(top); + if( DUChainUtils::argumentContext(dec) ) + parameters = DUChainUtils::argumentContext(dec)->localDeclarations(top); // QStringList defaultParams = decl->defaultParameters(); QVector::const_iterator paramNameIt = parameters.begin(); uint defaultParamNum = 0; int firstDefaultParam = functionType->arguments().count() - decl->defaultParametersSize(); int textFormatStart = ret.length(); ret += "("; if( highlighting && ret.length() != textFormatStart ) { //Add a default-highlighting for the passed text *highlighting << QVariant(textFormatStart); *highlighting << QVariant(ret.length() - textFormatStart); *highlighting << boldFormat; textFormatStart = ret.length(); } bool first = true; int num = 0; //const KDevVarLengthArray& conversions = f.function.parameterConversions(); int parameterConversion = 0; foreach (const AbstractType::Ptr& argument, functionType->arguments()) { if (first) { first = false; } else { ret += ", "; } bool doHighlight = false; QTextFormat doFormat = normalFormat; /*if( ( f.function.isValid() && num == f.matchedArguments ) ) { doHighlight = true; doFormat = highlightFormat; } else if( num < f.matchedArguments ) { doHighlight = true; QTextCharFormat format; if( parameterConversion != conversions.size() ) { //Interpolate the color quint64 badMatchColor = 0xff7777ff; //Full blue quint64 goodMatchColor = 0xff77ff77; //Full green uint totalColor = (badMatchColor*(Cpp::MaximumConversionResult-conversions[parameterConversion].rank) + goodMatchColor*(conversions[parameterConversion]).rank)/Cpp::MaximumConversionResult; format.setUnderlineStyle( QTextCharFormat::WaveUnderline ); format.setUnderlineColor( QColor(totalColor) ); ++parameterConversion; doFormat = format; } } if( doHighlight ) { if( highlighting && ret.length() != textFormatStart ) { //Add a default-highlighting for the passed text *highlighting << QVariant(textFormatStart); *highlighting << QVariant(ret.length() - textFormatStart); *highlighting << QVariant(normalFormat); textFormatStart = ret.length(); } }*/ if( paramNameIt != parameters.end() /*&& !(*paramNameIt)->identifier().isEmpty()*/ ) { if(noShortening) ret += argument->toString(); else ret += (*paramNameIt)->abstractType()->toString();// TODO Shorten ret += " " + (*paramNameIt)->identifier().toString(); } else if (argument) ret += argument->toString(); else ret += ""; if( doHighlight ) { if( highlighting && ret.length() != textFormatStart ) { *highlighting << QVariant(textFormatStart); *highlighting << QVariant(ret.length() - textFormatStart); *highlighting << doFormat; textFormatStart = ret.length(); } } if( num >= firstDefaultParam && includeDefaultParams ) { ret += " = "; QString defaultParam = decl->defaultParameters()[defaultParamNum].str(); if(defaultParam.length() <= 30) ret += defaultParam; else ret += "..."; ++defaultParamNum; } ++num; if( paramNameIt != parameters.end() ) ++paramNameIt; } if( highlighting && ret.length() != textFormatStart ) { *highlighting << QVariant(textFormatStart); *highlighting << QVariant(ret.length() - textFormatStart); *highlighting << normalFormat; textFormatStart = ret.length(); } ret += ')'; if( highlighting && ret.length() != textFormatStart ) { *highlighting << QVariant(textFormatStart); *highlighting << QVariant(ret.length() - textFormatStart); *highlighting << boldFormat; textFormatStart = ret.length(); } } return ret; } //Returns the type as which a declaration in the completion-list should be interpreted, which especially means that it returns the return-type of a function. AbstractType::Ptr effectiveType( Declaration* decl ) { if( !decl || !decl->abstractType() ) return AbstractType::Ptr(); if( decl->type() ) return decl->type()->returnType(); return decl->abstractType(); } } diff --git a/completion/items.cpp b/completion/items.cpp index 64a366e..4886705 100644 --- a/completion/items.cpp +++ b/completion/items.cpp @@ -1,135 +1,133 @@ /* * KDevelop Java Code Completion Support * * Copyright 2007-2008 David Nolden * Copyright 2008 Hamish Rodda * * This program 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 program 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "items.h" -#include - #include #include #include #include #include #include #include #include #include #include #include #include #include "helpers.h" using namespace KDevelop; namespace java { -NormalDeclarationCompletionItem::NormalDeclarationCompletionItem(KDevelop::DeclarationPointer decl, KSharedPtr< KDevelop::CodeCompletionContext > context, int _inheritanceDepth) +NormalDeclarationCompletionItem::NormalDeclarationCompletionItem(KDevelop::DeclarationPointer decl, QExplicitlySharedDataPointer< KDevelop::CodeCompletionContext > context, int _inheritanceDepth) : KDevelop::NormalDeclarationCompletionItem(decl, context, _inheritanceDepth) { } -void NormalDeclarationCompletionItem::executed(KTextEditor::Document* document, const KTextEditor::Range& word) +void NormalDeclarationCompletionItem::executed(KTextEditor::View* document, const KTextEditor::Range& word) { if( m_declaration && dynamic_cast(m_declaration.data()) ) { //Do some intelligent stuff for functions with the parens: insertFunctionParenText(document, word.end(), m_declaration); } } QVariant NormalDeclarationCompletionItem::data(const QModelIndex& index, int role, const KDevelop::CodeCompletionModel* model) const { DUChainReadLocker lock(DUChain::lock(), 500); if(!lock.locked()) { - kDebug() << "Failed to lock the du-chain in time"; + qDebug() << "Failed to lock the du-chain in time"; return QVariant(); } switch (role) { case Qt::DisplayRole: switch (index.column()) { case CodeCompletionModel::Prefix: { if(m_declaration->kind() == Declaration::Namespace) return "package"; if( NamespaceAliasDeclaration* alias = dynamic_cast(m_declaration.data()) ) { if( alias->identifier().isEmpty() ) { return "imported package"; } else { return "package"; } } if( m_declaration->kind() == Declaration::Type && !m_declaration->type() ) { if (java::ClassDeclaration* classDecl = dynamic_cast(m_declaration.data())) { switch (classDecl->classType()) { case ClassDeclarationData::Class: return "class"; break; case ClassDeclarationData::Interface: return "interface"; break; case ClassDeclarationData::Enum: return "enum"; break; } return QVariant(); } } break; } case CodeCompletionModel::Scope: { //The scopes are not needed return QVariant(); } case CodeCompletionModel::Arguments: if (FunctionType::Ptr functionType = m_declaration->type()) return createArgumentList(*this, 0); break; - + case CodeCompletionModel::Postfix: if (FunctionType::Ptr functionType = m_declaration->type()) { // TODO print throws declarations //return functionType->modifiers() & AbstractType::ConstModifier ? i18n("const") : QString(); } break; } break; } lock.unlock(); return KDevelop::NormalDeclarationCompletionItem::data(index, role, model); } QString NormalDeclarationCompletionItem::shortenedTypeString(KDevelop::DeclarationPointer decl, int desiredTypeLength) const { if (FunctionType::Ptr funType = decl->type()) return funType->returnType()->toString(); return KDevelop::NormalDeclarationCompletionItem::shortenedTypeString(decl, desiredTypeLength); } } diff --git a/completion/items.h b/completion/items.h index 4377358..61f4cee 100644 --- a/completion/items.h +++ b/completion/items.h @@ -1,47 +1,46 @@ /* * KDevelop Java Code Completion Support * * Copyright 2007-2008 David Nolden * Copyright 2008 Hamish Rodda * * This program 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 program 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef COMPLETIONITEM_H #define COMPLETIONITEM_H #include #include class QModelIndex; namespace java { - //A completion item used for completion of normal declarations while normal code-completion class NormalDeclarationCompletionItem : public KDevelop::NormalDeclarationCompletionItem { public: - NormalDeclarationCompletionItem(KDevelop::DeclarationPointer decl = KDevelop::DeclarationPointer(), KSharedPtr context=KSharedPtr(), int _inheritanceDepth = 0); + NormalDeclarationCompletionItem(KDevelop::DeclarationPointer decl = KDevelop::DeclarationPointer(), QExplicitlySharedDataPointer context=QExplicitlySharedDataPointer(), int _inheritanceDepth = 0); virtual QVariant data(const QModelIndex& index, int role, const KDevelop::CodeCompletionModel* model) const; protected: - virtual void executed(KTextEditor::Document* document, const KTextEditor::Range& word); + virtual void executed(KTextEditor::View* document, const KTextEditor::Range& word); virtual QString shortenedTypeString(KDevelop::DeclarationPointer decl, int desiredTypeLength) const; }; } #endif diff --git a/completion/model.cpp b/completion/model.cpp index a49ca76..aa4456a 100644 --- a/completion/model.cpp +++ b/completion/model.cpp @@ -1,72 +1,68 @@ /* * KDevelop Java Code Completion Support * * Copyright 2006-2008 Hamish Rodda * Copyright 2007-2008 David Nolden * * This program 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 program 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "model.h" #include #include #include #include #include -#include #include #include -#include -#include #include #include #include #include #include #include #include #include #include #include "context.h" #include "worker.h" #include "javalanguagesupport.h" using namespace KTextEditor; using namespace KDevelop; namespace java { CodeCompletionModel::CodeCompletionModel( QObject * parent ) : KDevelop::CodeCompletionModel(parent) { } CodeCompletionModel::~CodeCompletionModel() { } KDevelop::CodeCompletionWorker* CodeCompletionModel::createCompletionWorker() { return new CodeCompletionWorker(this); } } -#include "model.moc" diff --git a/completion/model.h b/completion/model.h index 9d15911..62f83c9 100644 --- a/completion/model.h +++ b/completion/model.h @@ -1,54 +1,53 @@ /* * KDevelop Java Code Completion Support * * Copyright 2006-2008 Hamish Rodda * Copyright 2007-2008 David Nolden * * This program 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 program 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDEVCPPCODECOMPLETIONMODEL_H #define KDEVCPPCODECOMPLETIONMODEL_H #include #include #include #include -#include #include #include "context.h" namespace java { class CodeCompletionModel : public KDevelop::CodeCompletionModel { Q_OBJECT public: CodeCompletionModel(QObject* parent); virtual ~CodeCompletionModel(); protected: virtual KDevelop::CodeCompletionWorker* createCompletionWorker(); - + private: - KSharedPtr m_completionContext; + QExplicitlySharedDataPointer m_completionContext; }; } #endif diff --git a/completion/worker.cpp b/completion/worker.cpp index 023235f..f80b627 100644 --- a/completion/worker.cpp +++ b/completion/worker.cpp @@ -1,53 +1,50 @@ /* * KDevelop Java Code Completion Support * * Copyright 2006-2008 Hamish Rodda * Copyright 2007-2008 David Nolden * * This program 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 program 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "worker.h" -#include - #include #include -#include #include #include #include #include #include #include #include "model.h" using namespace KDevelop; namespace java { CodeCompletionWorker::CodeCompletionWorker(CodeCompletionModel* parent) : KDevelop::CodeCompletionWorker(parent) { } KDevelop::CodeCompletionContext* CodeCompletionWorker::createCompletionContext(KDevelop::DUContextPointer context, const QString &contextText, const QString &followingText, const KDevelop::CursorInRevision &position) const { return new java::CodeCompletionContext(context, contextText, followingText, position); } } diff --git a/duchain/CMakeLists.txt b/duchain/CMakeLists.txt index 8836569..7c490a3 100644 --- a/duchain/CMakeLists.txt +++ b/duchain/CMakeLists.txt @@ -1,42 +1,34 @@ add_subdirectory(tests) set(kdevjavaduchain_SRCS helpers.cpp editorintegrator.cpp identifiercompiler.cpp contextbuilder.cpp dumpchain.cpp declarationbuilder.cpp usebuilder.cpp typebuilder.cpp classdeclaration.cpp expressionvisitor.cpp topducontext.cpp overloadresolver.cpp typeconversion.cpp typeutils.cpp viablefunctions.cpp ) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../parser ${CMAKE_CURRENT_BINARY_DIR}/../parser ${CMAKE_CURRENT_BINARY_DIR} - ${KDE4_INCLUDES} - ${KDEVPLATFORM_INCLUDE_DIR} ) -kde4_add_library(kdevjavaduchain SHARED ${kdevjavaduchain_SRCS} ) +add_library(kdevjavaduchain SHARED ${kdevjavaduchain_SRCS} ) +generate_export_header(kdevjavaduchain BASE_NAME javaduchain EXPORT_MACRO_NAME KDEVJAVADUCHAIN_EXPORT) target_link_libraries(kdevjavaduchain - ${QT_QTDESIGNER_LIBRARY} - ${KDE4_KTEXTEDITOR_LIBS} - ${KDEVPLATFORM_INTERFACES_LIBRARIES} - ${KDEVPLATFORM_PROJECT_LIBRARIES} - ${KDE4_THREADWEAVER_LIBRARIES} - ${KDEVPLATFORM_LANGUAGE_LIBRARIES} - ${KDE4_KDEUI_LIBS} kdev4javaparser ) install(TARGETS kdevjavaduchain DESTINATION ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/duchain/abstractexpressionvisitor.h b/duchain/abstractexpressionvisitor.h index 07f7ffc..02aa30d 100644 --- a/duchain/abstractexpressionvisitor.h +++ b/duchain/abstractexpressionvisitor.h @@ -1,201 +1,201 @@ /* Copyright 2007 David Nolden Copyright 2009 Hamish Rodda 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. */ #ifndef KDEVPLATFORM_ABSTRACTEXPRESSIONVISITOR_H #define KDEVPLATFORM_ABSTRACTEXPRESSIONVISITOR_H #include #include #include namespace KDevelop { template class AbstractExpressionVisitor : public LanguageSpecificExpressionVisitorBase { public: AbstractExpressionVisitor() { } struct Instance { Instance() : isInstance(false) { } Instance( bool is ) : isInstance(is) { } Instance( DeclarationPointer decl ) : isInstance(true), declaration(decl) { } Instance( Declaration* decl ) : isInstance(true), declaration(DeclarationPointer(decl)) { } inline operator bool() const { return isInstance; } bool isInstance; DeclarationPointer declaration; //May contain the declaration of the instance, but only when isInstance is true. May also contain type-declaration, which signalizes that this is an instance of that type. }; void parse( T* ast ) { m_lastType = 0; m_lastInstance = Instance(); DUContext* context = ast->ducontext; Q_ASSERT(context); m_topContext = context->topContext(); this->visitNode(ast); m_topContext = 0; flushUse(); } const KDevelop::AbstractType::Ptr lastType() const { return m_lastType; } void setLastType(KDevelop::AbstractType::Ptr type) { m_lastType = type; } void setInstantiatedType(bool instantiated = true) { m_lastInstance = Instance(instantiated); } void setInstantiatedType(KDevelop::AbstractType::Ptr type, bool instantiated = true) { m_lastType = type; m_lastInstance = Instance(instantiated); } template void setLastType(TypePtr type) { m_lastType = AbstractType::Ptr::staticCast(type); } const Instance lastInstance() const { return m_lastInstance; } void setLastInstance(Declaration* decl) { m_lastInstance = Instance(decl); if (decl) m_lastType = decl->abstractType(); else m_lastType = 0; } protected: KDevelop::AbstractType::Ptr lastType() { return m_lastType; } Instance lastInstance() { return m_lastInstance; } /** * Will be called for each relevant sub-node with the resolved type of that expression. This is not guaranteed to be called. * There is also no guarantee in which order expressionType() will be called. * The du-chain will not be locked in the moment this is called. * * @param node the AST-Node * @param type the type the expression in the AST-node evaluates to * @param instance If the expression evaluates to an instance of a type, this contains information about that instance. declaration is only filled for explicitly declared instances. * If this is zero, the expression evaluates to a type. * * Warning: * In case of temporary instances, decl will be the declaration of the basic type, not of an instance. * Since temporary instances are never declared, there's no other way. * * examples: * the expression "AbstractType::Ptr" evaluates to a type, so @param type would be filled and @param decl would be zero. * When the context contains "AbstractType::Ptr ptr;", the expression "ptr" will evaluate to an instance of * AbstractType::Ptr, so @param type will contain the type AbstractType::Ptr, and @param decl will point to the declaration of ptr. * * Problem: **/ virtual void expressionType( T* node, const AbstractType::Ptr& type, Instance instance ) { Q_UNUSED(node) Q_UNUSED(type) Q_UNUSED(instance) } /** The duchain is not locked when this is called */ virtual void usingDeclaration( T* node, const KDevelop::DeclarationPointer& decl, TokenType start_token = TokenType(), TokenType end_token = TokenType() ) { usingDeclaration(node, start_token, end_token, decl); } virtual void usingDeclaration( T* node, TokenType start_token, TokenType end_token, const KDevelop::DeclarationPointer& decl ) { Q_UNUSED(node) Q_UNUSED(start_token) Q_UNUSED(end_token) Q_UNUSED(decl) } /** Called when there is a problem, with a string for that problem. * The default-implementation dumps all relevant information to - * kDebug. + * qDebug. * @param node the node the problem is about * @param str a string that describes the problem */ virtual void problem( T* node, const QString& str ) { #ifdef DUMP_PROBLEMS - kDebug() << "Problem:" << str; + qDebug() << "Problem:" << str; #endif } void flushUse() { if( m_currentUse.isValid ) usingDeclaration( m_currentUse.node, m_currentUse.start_token, m_currentUse.end_token, m_currentUse.declaration ); m_currentUse.isValid = false; } struct CurrentUse { CurrentUse() : isValid(false), start_token(0), end_token(0) { } bool isValid; T* node; TokenType start_token, end_token; KDevelop::DeclarationPointer declaration; } m_currentUse; //This is used to temporarily delay the calling of usingDeclaration. KDevelop::TopDUContext* topContext() const { return m_topContext; } private: KDevelop::AbstractType::Ptr m_lastType; Instance m_lastInstance; //Contains whether the last evaluation resulted in an instance, and maybe the instance-declaration const KDevelop::TopDUContext* m_source; //Whenever a list of declarations is queried, it is stored here. Especially in visitName(...) and findMember(...) QList m_lastDeclarations; KDevelop::DUContext* m_currentContext; KDevelop::TopDUContext* m_topContext; }; } #endif // KDEVPLATFORM_ABSTRACTEXPRESSIONVISITOR_H diff --git a/duchain/classdeclaration.cpp b/duchain/classdeclaration.cpp index b0ac15c..19c589f 100644 --- a/duchain/classdeclaration.cpp +++ b/duchain/classdeclaration.cpp @@ -1,94 +1,105 @@ /* This is part of KDevelop Copyright 2007 David Nolden Copyright 2008 Hamish Rodda 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. */ #include "classdeclaration.h" #include #include #include #include using namespace KDevelop; namespace java { DEFINE_LIST_MEMBER_HASH(ClassDeclarationData, baseClasses, BaseClassInstance) ClassDeclaration::ClassDeclaration(const KDevelop::RangeInRevision& range, DUContext* context) : ClassMemberDeclaration(*new ClassDeclarationData, range) { d_func_dynamic()->setClassId(this); setContext(context); } ClassDeclaration::ClassDeclaration(ClassDeclarationData& data) : ClassMemberDeclaration(data) { } REGISTER_DUCHAIN_ITEM(ClassDeclaration); + +void ClassDeclaration::setStorageSpecifiers(StorageSpecifiers specifiers) +{ + ClassMemberDeclaration::setStorageSpecifiers(ClassMemberDeclaration::StorageSpecifiers(static_cast(specifiers))); + this->m_isFinal = specifiers & FinalSpecifier; + this->m_isSynchronized = specifiers & SynchronizedSpecifier; + this->m_isNative = specifiers & NativeSpecifier; + this->m_isStrictFP = specifiers & StrictFPSpecifier; + this->m_isAbstract = specifiers & AbstractSpecifier; +} + void ClassDeclaration::clearBaseClasses() { d_func_dynamic()->baseClassesList().clear(); } uint ClassDeclaration::baseClassesSize() const { return d_func()->baseClassesSize(); } const BaseClassInstance* ClassDeclaration::baseClasses() const { return d_func()->baseClasses(); } void ClassDeclaration::addBaseClass(BaseClassInstance klass) { d_func_dynamic()->baseClassesList().append(klass); } void ClassDeclaration::replaceBaseClass(uint n, BaseClassInstance klass) { Q_ASSERT(n <= d_func_dynamic()->baseClassesSize()); d_func_dynamic()->baseClassesList()[n] = klass; } ClassDeclaration::~ClassDeclaration() { } ClassDeclaration::ClassDeclaration(const ClassDeclaration& rhs) : ClassMemberDeclaration(*new ClassDeclarationData(*rhs.d_func())) { d_func_dynamic()->setClassId(this); } Declaration* ClassDeclaration::clonePrivate() const { return new ClassDeclaration(*this); } QString ClassDeclaration::toString() const { return (classType() == ClassDeclarationData::Class ? "class " : "interface ") + identifier().toString(); } ClassDeclarationData::ClassType ClassDeclaration::classType() const { return d_func()->m_classType; } void ClassDeclaration::setClassType(java::ClassDeclarationData::ClassType type) { d_func_dynamic()->m_classType = type; } } diff --git a/duchain/classdeclaration.h b/duchain/classdeclaration.h index 9a3e884..ebe5b1f 100644 --- a/duchain/classdeclaration.h +++ b/duchain/classdeclaration.h @@ -1,120 +1,145 @@ /* This file is part of KDevelop Copyright 2008 David Nolden Copyright 2008-2009 Hamish Rodda 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. */ #ifndef CLASSDECLARATION_H #define CLASSDECLARATION_H #include #include #include #include #include -#include "javaduchainexport.h" +#include "javaduchain_export.h" namespace KDevelop { class QualifiedIdentifier; class DUContext; class TopDUContext; class HashedString; class RangeInRevision; } namespace java { struct BaseClassInstance { KDevelop::IndexedType baseClass; }; DECLARE_LIST_MEMBER_HASH(ClassDeclarationData, baseClasses, BaseClassInstance) class ClassDeclarationData : public KDevelop::ClassMemberDeclarationData { public: enum ClassType { Class, Interface, Enum }; ClassDeclarationData() : m_classType(Class) { initializeAppendedLists(); } ~ClassDeclarationData() { freeAppendedLists(); } ClassDeclarationData(const ClassDeclarationData& rhs) : KDevelop::ClassMemberDeclarationData(rhs) { initializeAppendedLists(); copyListsFrom(rhs); m_classType = rhs.m_classType; } /// Type of the class (class or interface) ClassType m_classType; START_APPENDED_LISTS_BASE(ClassDeclarationData, KDevelop::ClassMemberDeclarationData); APPENDED_LIST_FIRST(ClassDeclarationData, BaseClassInstance, baseClasses); END_APPENDED_LISTS(ClassDeclarationData, baseClasses); }; class KDEVJAVADUCHAIN_EXPORT ClassDeclaration : public KDevelop::ClassMemberDeclaration { public: + ClassDeclaration(const ClassDeclaration& rhs); ClassDeclaration(ClassDeclarationData& data); ClassDeclaration(const KDevelop::RangeInRevision& range, KDevelop::DUContext* context); ~ClassDeclaration(); + enum StorageSpecifier { + StaticSpecifier = 0x1 /**< indicates static member */, + AutoSpecifier = 0x2 /**< indicates automatic determination of member access */, + FriendSpecifier = 0x4 /**< indicates friend member */, + ExternSpecifier = 0x8 /**< indicates external declaration */, + RegisterSpecifier = 0x10 /**< indicates register */, + MutableSpecifier = 0x20 /**< indicates a mutable member */, + FinalSpecifier = 0x40 /**< indicates a final declaration */, + NativeSpecifier = 0x80, + SynchronizedSpecifier = 0x100, + StrictFPSpecifier = 0x200, + AbstractSpecifier = 0x400 + }; + Q_DECLARE_FLAGS(StorageSpecifiers, StorageSpecifier) + + void setStorageSpecifiers(StorageSpecifiers specifiers); + void clearBaseClasses(); ///Count of base-classes uint baseClassesSize() const; ///The types this class is based on const BaseClassInstance* baseClasses() const; void addBaseClass(BaseClassInstance klass); //Replaces the n'th base-class with the given one. The replaced base-class must have existed. void replaceBaseClass(uint n, BaseClassInstance klass); /**Returns whether base is a public base-class of this class * @param baseConversionLevels If nonzero, this will count the distance of the classes. * */ //bool isPublicBaseClass( ClassDeclaration* base, const KDevelop::TopDUContext* topContext, int* baseConversionLevels = 0 ) const; virtual QString toString() const; void setClassType(ClassDeclarationData::ClassType type); ClassDeclarationData::ClassType classType() const; enum { Identity = 30 }; private: virtual KDevelop::Declaration* clonePrivate() const; DUCHAIN_DECLARE_DATA(ClassDeclaration) + + bool m_isFinal = false; + bool m_isNative = false; + bool m_isSynchronized = false; + bool m_isStrictFP = false; + bool m_isAbstract = false; + }; } #endif // FUNCTIONDECLARATION_H diff --git a/duchain/contextbuilder.cpp b/duchain/contextbuilder.cpp index 2ce1add..b468080 100644 --- a/duchain/contextbuilder.cpp +++ b/duchain/contextbuilder.cpp @@ -1,467 +1,466 @@ /* This file is part of KDevelop Copyright 2006 Roberto Raggi Copyright 2006-2009 Hamish Rodda 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. */ #include "contextbuilder.h" -#include -#include +#include #include #include #include #include "parsesession.h" #include "editorintegrator.h" #include "identifiercompiler.h" #include "topducontext.h" #include "helpers.h" using namespace KTextEditor; using namespace KDevelop; namespace java { ContextBuilder::ContextBuilder() : m_identifierCompiler(0) , m_editor(0) , m_mapAst(false) , m_computeOnlyVisible(false) { } bool ContextBuilder::onlyComputeVisible() const { return m_computeOnlyVisible; } void ContextBuilder::setOnlyComputeVisible(bool onlyVisible) { m_computeOnlyVisible = onlyVisible; } void ContextBuilder::unresolvedIdentifier(KDevelop::DUContextPointer context, KDevelop::QualifiedIdentifier id) { m_unresolvedIDs.append(ContextID(context, id)); } bool ContextBuilder::identifiersRemainUnresolved() const { DUChainReadLocker lock(DUChain::lock()); - + foreach (const ContextID& cid, m_unresolvedIDs) { // Weirdness if the context has been deleted if (!cid.first) return false; if (cid.first->findDeclarations(cid.second).isEmpty()) return true; } return false; } bool ContextBuilder::hadUnresolvedIdentifiers() const { return !m_unresolvedIDs.isEmpty(); } KDevelop::TopDUContext* ContextBuilder::newTopContext(const KDevelop::RangeInRevision& range, KDevelop::ParsingEnvironmentFile* file) { KDevelop::IndexedString rangeUrl = editor()->parseSession()->m_document; if (!file) { file = new ParsingEnvironmentFile(rangeUrl); /// Indexed string for 'Java', identifies environment files from this language plugin static const IndexedString javaLangString("Java"); file->setLanguage(javaLangString); } TopDUContext* top = new java::TopDUContext(rangeUrl, range, file); Q_ASSERT(top); ReferencedTopDUContext global = allJavaContext(); Q_ASSERT(global); top->addImportedParentContext(global); global->addImportedParentContext(top); return top; } KDevelop::DUContext* ContextBuilder::newContext(const KDevelop::RangeInRevision& range) { return new DUContext(range, currentContext()); } void ContextBuilder::setEditor(EditorIntegrator* editor) { m_editor = editor; m_identifierCompiler = new IdentifierCompiler(editor->parseSession()); } void ContextBuilder::setEditor(ParseSession* session) { EditorIntegrator* editor = new EditorIntegrator(session); setEditor(editor); } ContextBuilder::~ContextBuilder () { delete m_identifierCompiler; } void ContextBuilder::startVisiting( AstNode* node ) { visitNode(node); } void ContextBuilder::setContextOnNode( AstNode* node, KDevelop::DUContext* ctx ) { node->ducontext = ctx; } KDevelop::DUContext* ContextBuilder::contextFromNode( AstNode* node ) { return node->ducontext; } EditorIntegrator* ContextBuilder::editor() const { return m_editor; } KDevelop::RangeInRevision ContextBuilder::editorFindRange( AstNode* fromRange, AstNode* toRange ) { return editor()->findRange(fromRange, toRange); } QualifiedIdentifier ContextBuilder::identifierForNode(IdentifierAst* id) { if( !id ) return QualifiedIdentifier(); m_identifierCompiler->run(id); return m_identifierCompiler->identifier(); } KDevelop::QualifiedIdentifier ContextBuilder::identifierForNode(java::QualifiedIdentifierAst* id) { if( !id ) return QualifiedIdentifier(); m_identifierCompiler->run(id); return m_identifierCompiler->identifier(); } QualifiedIdentifier ContextBuilder::identifierForNode(ClassOrInterfaceTypeNameAst* id) { if( !id ) return QualifiedIdentifier(); m_identifierCompiler->run(id); return m_identifierCompiler->identifier(); } KDevelop::QualifiedIdentifier ContextBuilder::identifierForNode(const KDevPG::ListNode* id) { if( !id ) return QualifiedIdentifier(); QualifiedIdentifier result; const KDevPG::ListNode *__it = id->front(), *__end = __it; do { m_identifierCompiler->run(__it->element); result.push(m_identifierCompiler->identifier()); __it = __it->next; } while (__it != __end); return result; } void ContextBuilder::visitClassDeclaration(ClassDeclarationAst * node) { //visitNode(node->className); QualifiedIdentifier id = identifierForNode(node->className); visitNode(node->modifiers); visitNode(node->typeParameters); openContext(node->body, DUContext::Class, id); classContextOpened(currentContext()); visitNode(node->extends); visitNode(node->implements); visitNode(node->body); closeContext(); } void ContextBuilder::visitInterfaceDeclaration(InterfaceDeclarationAst * node) { visitNode(node->modifiers); //visitNode(node->interfaceName); QualifiedIdentifier id = identifierForNode(node->interfaceName); visitNode(node->typeParameters); openContext(node->body, DUContext::Class, id); classContextOpened(currentContext()); visitNode(node->extends); visitNode(node->body); closeContext(); } void ContextBuilder::visitEnumDeclaration(java::EnumDeclarationAst* node) { QualifiedIdentifier id = identifierForNode(node->enumName); openContext(node->body, DUContext::Class, id); classContextOpened(currentContext()); - + DefaultVisitor::visitEnumDeclaration(node); closeContext(); } void ContextBuilder::visitMethodDeclaration(MethodDeclarationAst * node) { visitNode(node->modifiers); visitNode(node->typeParameters); // Called by type builder //visitNode(node->returnType); // Called by openContext -> identifierForName //visitNode(node->methodName); QualifiedIdentifier id; KDevelop::DUContext* parameters = 0; if (node->parameters) { parameters = openContext(node->parameters, DUContext::Function, node->methodName); id = currentContext()->localScopeIdentifier(); visitNode(node->parameters); closeContext(); } visitNode(node->declaratorBrackets); visitNode(node->throwsClause); if (!onlyComputeVisible() && node->body) { KDevelop::DUContext* body = openContext(node->body, DUContext::Other, id); if (parameters) { DUChainWriteLocker lock(DUChain::lock()); body->addImportedParentContext(parameters); } visitNode(node->body); closeContext(); } } void ContextBuilder::visitForStatement(ForStatementAst *node) { KDevelop::DUContext* control = 0; if (node->forControl) { control = openContext(node->forControl, DUContext::Other, 0); visitNode(node->forControl); closeContext(); } if (node->forBody) { KDevelop::DUContext* body = openContext(node->forBody, DUContext::Other, 0); if (control) { DUChainWriteLocker lock(DUChain::lock()); body->addImportedParentContext(control); } visitNode(node->forBody); closeContext(); } } void ContextBuilder::visitIfStatement(IfStatementAst * node) { KDevelop::DUContext* condition = 0; if (node->condition) { condition = openContext(node->condition, DUContext::Other, 0); visitNode(node->condition); closeContext(); } if (node->ifBody) { KDevelop::DUContext* body = openContext(node->ifBody, DUContext::Other, 0); if (condition) { DUChainWriteLocker lock(DUChain::lock()); body->addImportedParentContext(condition); } visitNode(node->ifBody); closeContext(); } if (node->elseBody) { KDevelop::DUContext* body = openContext(node->elseBody, DUContext::Other, 0); if (condition) { DUChainWriteLocker lock(DUChain::lock()); body->addImportedParentContext(condition); } visitNode(node->elseBody); closeContext(); } } void ContextBuilder::visitConstructorDeclaration(ConstructorDeclarationAst * node) { visitNode(node->modifiers); visitNode(node->typeParameters); //visitNode(node->className); QualifiedIdentifier id; KDevelop::DUContext* parameters = 0; if (node->parameters) { parameters = openContext(node->parameters, DUContext::Other, node->className); id = currentContext()->localScopeIdentifier(); visitNode(node->parameters); closeContext(); } visitNode(node->throwsClause); if (!onlyComputeVisible() && node->body) { KDevelop::DUContext* body = openContext(node->body, DUContext::Class, id); if (parameters) { DUChainWriteLocker lock(DUChain::lock()); body->addImportedParentContext(parameters); } visitNode(node->body); closeContext(); } } void ContextBuilder::visitCompilationUnit(java::CompilationUnitAst* node) { if (node->importDeclarationSequence) visitNodeList(node->importDeclarationSequence); else visitImportDeclaration(0); KDevelop::DUContext* packageContext = currentContext(); bool openedExtraContext = false; QualifiedIdentifier id; if (node->packageDeclaration && node->packageDeclaration->packageName) { id = identifierForNode(node->packageDeclaration->packageName); if (id.count() > 1) { openContext(node, DUContext::Namespace, id.left(-1)); packageContext = currentContext(); openedExtraContext = true; } } - + if (node->packageDeclaration) visitPackageDeclaration(node->packageDeclaration); if (openedExtraContext) closeContext(); QList packageDeclarations; { DUChainReadLocker lock(DUChain::lock()); packageDeclarations = packageContext->findLocalDeclarations(id.last()); if (id.isEmpty()) { Q_ASSERT(packageDeclarations.isEmpty()); } else if (packageDeclarations.count() != 1) { - kWarning() << "Package declaration expected, found " << packageDeclarations.count() << "declarations of" << id.last().toString(); + qWarning() << "Package declaration expected, found " << packageDeclarations.count() << "declarations of" << id.last().toString(); } } openContext(node, DUContext::Namespace, id); if (!packageDeclarations.isEmpty()) { DUChainWriteLocker lock(DUChain::lock()); packageDeclarations.first()->setInternalContext(currentContext()); } visitNodeList(node->typeDeclarationSequence); closeContext(); } void ContextBuilder::addBaseType(BaseClassInstance base) { DUChainWriteLocker lock(DUChain::lock()); //addImportedContexts(); //Make sure the template-contexts are imported first, before any parent-class contexts. if (currentContext()->type() != DUContext::Class) { - kDebug() << "Tried to add base class to a non-class context!"; + qDebug() << "Tried to add base class to a non-class context!"; return; } AbstractType::Ptr baseClass = base.baseClass.abstractType(); - IdentifiedType* idType = dynamic_cast(baseClass.unsafeData()); + IdentifiedType* idType = dynamic_cast(baseClass.data()); Declaration* idDecl = 0; if (idType) { idDecl = idType->declaration(currentContext()->topContext()); if (!idDecl) { - kDebug() << "No declaration provided by base class type " << idType->qualifiedIdentifier().toStringList().join("."); + qDebug() << "No declaration provided by base class type " << idType->qualifiedIdentifier().toStringList().join("."); return; } } else { - kDebug() << "Tried to add base class which is a null type!"; + qDebug() << "Tried to add base class which is a null type!"; return; } - + if( idDecl->logicalInternalContext(0) ) { currentContext()->addImportedParentContext( idDecl->logicalInternalContext(0) ); } else { - kDebug() << "No internal context provided for " << idDecl->toString(); + qDebug() << "No internal context provided for " << idDecl->toString(); } } void ContextBuilder::classContextOpened(KDevelop::DUContext* context) { Q_UNUSED(context); } void ContextBuilder::visitImportDeclaration(java::ImportDeclarationAst* node) { if (node) DefaultVisitor::visitImportDeclaration(node); } } diff --git a/duchain/contextbuilder.h b/duchain/contextbuilder.h index dae97f8..aaf2ab0 100644 --- a/duchain/contextbuilder.h +++ b/duchain/contextbuilder.h @@ -1,129 +1,129 @@ /* This file is part of KDevelop Copyright 2006 Roberto Raggi Copyright 2006-2008 Hamish Rodda 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. */ #ifndef CONTEXTBUILDER_H #define CONTEXTBUILDER_H #include "javadefaultvisitor.h" #include #include "classdeclaration.h" -#include "javaduchainexport.h" +#include "javaduchain_export.h" class JavaLanguageSupport; namespace java { class EditorIntegrator; class IdentifierCompiler; class ParseSession; typedef KDevelop::AbstractContextBuilder ContextBuilderBase; /** * A class which iterates the AST to identify contexts. */ class KDEVJAVADUCHAIN_EXPORT ContextBuilder: public ContextBuilderBase, protected DefaultVisitor { public: ContextBuilder(); virtual ~ContextBuilder (); void setEditor(EditorIntegrator* editor); void setEditor(ParseSession* session); typedef QPair ContextID; const QList& unresolvedIdentifiers() const; bool hadUnresolvedIdentifiers() const; bool identifiersRemainUnresolved() const; bool onlyComputeVisible() const; void setOnlyComputeVisible(bool onlyVisible); protected: EditorIntegrator* editor() const; virtual KDevelop::TopDUContext* newTopContext(const KDevelop::RangeInRevision& range, KDevelop::ParsingEnvironmentFile* file = 0); virtual KDevelop::DUContext* newContext(const KDevelop::RangeInRevision& range); virtual void startVisiting( AstNode* node ); virtual void setContextOnNode( AstNode* node, KDevelop::DUContext* ctx ); virtual KDevelop::DUContext* contextFromNode( AstNode* node ); virtual KDevelop::RangeInRevision editorFindRange( AstNode* fromRange, AstNode* toRange ); /** * Compile an identifier for the specified AstNode \a id. * * \note this reference will only be valid until the next time the function * is called, so you need to create a copy (store as non-reference). * @param typeSpecifier a pointer that will eventually be filled with a type-specifier that can be found in the name(for example the return-type of a cast-operator) */ virtual KDevelop::QualifiedIdentifier identifierForNode(IdentifierAst* id); KDevelop::QualifiedIdentifier identifierForNode(QualifiedIdentifierAst* id); KDevelop::QualifiedIdentifier identifierForNode(const KDevPG::ListNode* id); KDevelop::QualifiedIdentifier identifierForNode(ClassOrInterfaceTypeNameAst* id); void unresolvedIdentifier(KDevelop::DUContextPointer context, KDevelop::QualifiedIdentifier id); - + // Visitors template void visitNodeList(const KDevPG::ListNode* list) { if (list) { const KDevPG::ListNode *__it = list->front(), *__end = __it; do { visitNode(__it->element); __it = __it->next; } while (__it != __end); } } virtual void visitCompilationUnit(java::CompilationUnitAst* node); virtual void visitForStatement(ForStatementAst *node); virtual void visitIfStatement(IfStatementAst *node); virtual void visitClassDeclaration(ClassDeclarationAst *node); virtual void visitMethodDeclaration(MethodDeclarationAst *node); virtual void visitConstructorDeclaration(ConstructorDeclarationAst *node); virtual void visitInterfaceDeclaration(InterfaceDeclarationAst *node); virtual void visitEnumDeclaration(java::EnumDeclarationAst* node); virtual void visitImportDeclaration(java::ImportDeclarationAst* node); virtual void addBaseType( BaseClassInstance base ); virtual void classContextOpened(KDevelop::DUContext* context); // Variables IdentifierCompiler* m_identifierCompiler; private: QList m_unresolvedIDs; EditorIntegrator* m_editor; public: bool m_mapAst; bool m_computeOnlyVisible; }; } #endif // CONTEXTBUILDER_H diff --git a/duchain/declarationbuilder.cpp b/duchain/declarationbuilder.cpp index 173407f..99de5b1 100644 --- a/duchain/declarationbuilder.cpp +++ b/duchain/declarationbuilder.cpp @@ -1,457 +1,454 @@ /* This file is part of KDevelop Copyright 2006-2008 Hamish Rodda 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. */ #include "declarationbuilder.h" #include -#include -#include - #include "editorintegrator.h" #include "identifiercompiler.h" #include #include #include "parsesession.h" #include "classdeclaration.h" #include #include "helpers.h" using namespace KTextEditor; using namespace KDevelop; namespace java { DeclarationBuilder::DeclarationBuilder (EditorIntegrator* editor) : m_defaultImportCreated(false) , m_inImplementsClause(false) , javaLang("java::lang::*") { setEditor(editor); } void DeclarationBuilder::closeDeclaration() { if (currentDeclaration()) { DUChainWriteLocker lock(DUChain::lock()); if (lastType()) { AbstractType::Ptr type = lastType(); - IdentifiedType* idType = dynamic_cast(type.unsafeData()); + IdentifiedType* idType = dynamic_cast(type.data()); //When the given type has no declaration yet, assume we are declaring it now. //If the type is a delayed type, it is a searched type, and not a declared one, so don't set the declaration then. if( idType && !idType->declarationId().isValid() /*&& !delayed*/ ) { idType->setDeclaration( currentDeclaration() ); } } - + currentDeclaration()->setType(lastType()); } eventuallyAssignInternalContext(); - //kDebug() << "Declaration closed:" << currentDeclaration()->identifier(); + //qDebug() << "Declaration closed:" << currentDeclaration()->identifier(); DeclarationBuilderBase::closeDeclaration(); } void DeclarationBuilder::visitClassDeclaration(ClassDeclarationAst * node) -{ +{ ClassDeclaration* newClass = openDefinition(node->className, node); newClass->setAccessPolicy(parseAccessPolicy(node->modifiers)); newClass->setClassType(ClassDeclarationData::Class); newClass->setStorageSpecifiers(parseModifiers(node->modifiers)); newClass->setKind(Declaration::Type); DeclarationBuilderBase::visitClassDeclaration(node); // Provide java.lang.Object inheritance where it is not specified DUChainWriteLocker lock(DUChain::lock()); //TODO : only count objects, not interfaces, in this check if (buildCompleteTypes() && newClass->baseClassesSize() == 0) { static QualifiedIdentifier javaLangObject("java::lang::Object"); if (newClass->qualifiedIdentifier() != javaLangObject) { QList declarations = currentContext()->findDeclarations(javaLangObject, currentContext()->range().end, AbstractType::Ptr(), currentContext()->topContext()); if (declarations.count() >= 1) { if (declarations.count() > 1) { - kDebug() << "Found mulitple declarations for" << javaLangObject.toStringList().join("."); + qDebug() << "Found mulitple declarations for" << javaLangObject.toStringList().join("."); } BaseClassInstance instance; { // TODO check that type is a class instance.baseClass = declarations.at(0)->indexedType(); - Q_ASSERT(dynamic_cast(instance.baseClass.abstractType().unsafeData())->declaration(currentContext()->topContext())); + Q_ASSERT(dynamic_cast(instance.baseClass.abstractType().data())->declaration(currentContext()->topContext())); newClass->addBaseClass(instance); } addBaseType(instance); } else { - kDebug() << "Couldn't find declaration for java.lang.Object"; + qDebug() << "Couldn't find declaration for java.lang.Object"; } } } closeDeclaration(); } void DeclarationBuilder::classContextOpened(KDevelop::DUContext* context) { if (currentDeclaration()) { DUChainWriteLocker lock(DUChain::lock()); Q_ASSERT(context->type() == KDevelop::DUContext::Class); currentDeclaration()->setInternalContext(context); } - + DeclarationBuilderBase::classContextOpened(context); } void DeclarationBuilder::visitClassExtendsClause(java::ClassExtendsClauseAst* node) { DeclarationBuilderBase::visitClassExtendsClause(node); if (buildCompleteTypes()) { BaseClassInstance instance; { DUChainWriteLocker lock(DUChain::lock()); ClassDeclaration* currentClass = dynamic_cast(currentDeclaration()); if (currentClass) { // TODO check that type is a class instance.baseClass = lastType()->indexed(); - kDebug() << "adding base class type, valid? " << instance.baseClass.isValid(); + qDebug() << "adding base class type, valid? " << instance.baseClass.isValid(); if (instance.baseClass.abstractType()) - kDebug() << "type " << instance.baseClass.abstractType()->toString(); + qDebug() << "type " << instance.baseClass.abstractType()->toString(); else - kDebug() << "null type"; + qDebug() << "null type"; if (instance.baseClass.isValid()) currentClass->addBaseClass(instance); else - kDebug() << "extends-specifier without class type (invalid parsed type)"; + qDebug() << "extends-specifier without class type (invalid parsed type)"; } else { - kDebug() << "extends-specifier without class type"; + qDebug() << "extends-specifier without class type"; } } addBaseType(instance); } } void DeclarationBuilder::visitImplementsClause(java::ImplementsClauseAst* node) { m_inImplementsClause = true; DeclarationBuilderBase::visitImplementsClause(node); m_inImplementsClause = false; } - + void DeclarationBuilder::visitClassOrInterfaceTypeName(ClassOrInterfaceTypeNameAst *node) { DeclarationBuilderBase::visitClassOrInterfaceTypeName(node); if (buildCompleteTypes()) { if (m_inImplementsClause) { BaseClassInstance instance; { DUChainWriteLocker lock(DUChain::lock()); ClassDeclaration* currentClass = dynamic_cast(currentDeclaration()); if(currentClass) { // TODO check that type is an interface instance.baseClass = lastType()->indexed(); currentClass->addBaseClass(instance); }else{ - kWarning() << "implements specifier without interface type"; + qWarning() << "implements specifier without interface type"; } } addBaseType(instance); } } } void DeclarationBuilder::visitInterfaceDeclaration(InterfaceDeclarationAst * node) { ClassDeclaration* newInterface = openDefinition(node->interfaceName, node); newInterface->setAccessPolicy(parseAccessPolicy(node->modifiers)); newInterface->setClassType(java::ClassDeclarationData::Interface); newInterface->setStorageSpecifiers(parseModifiers(node->modifiers)); newInterface->setKind(Declaration::Type); DeclarationBuilderBase::visitInterfaceDeclaration(node); // No default inheritance for interfaces closeDeclaration(); } void DeclarationBuilder::visitInterfaceMethodDeclaration(InterfaceMethodDeclarationAst * node) { ClassFunctionDeclaration* newMethod = openDefinition(node->methodName, node); newMethod->setKind(Declaration::Type); if (node->modifiers) { Declaration::AccessPolicy access = parseAccessPolicy(node->modifiers); // Default public access for interface methods if (access == Declaration::DefaultAccess) access = Declaration::Public; newMethod->setAccessPolicy(access); - newMethod->setStorageSpecifiers(parseModifiers(node->modifiers)); + newMethod->setStorageSpecifiers(ClassMemberDeclaration::StorageSpecifiers(static_cast(parseModifiers(node->modifiers)))); } DeclarationBuilderBase::visitInterfaceMethodDeclaration(node); closeDeclaration(); } void DeclarationBuilder::visitEnumDeclaration(java::EnumDeclarationAst* node) { ClassDeclaration* newInterface = openDefinition(node->enumName, node); newInterface->setAccessPolicy(parseAccessPolicy(node->modifiers)); newInterface->setStorageSpecifiers(parseModifiers(node->modifiers)); newInterface->setKind(Declaration::Type); DeclarationBuilderBase::visitEnumDeclaration(node); closeDeclaration(); } void DeclarationBuilder::visitEnumConstant(java::EnumConstantAst* node) { ClassMemberDeclaration* decl = openDeclaration(node->identifier, node); decl->setStatic(true); decl->setKind(Declaration::Instance); DeclarationBuilderBase::visitEnumConstant(node); EnumeratorType::Ptr enumeratorType = lastType().cast(); closeDeclaration(); if(enumeratorType) { ///@todo Move this into closeDeclaration in a logical way DUChainWriteLocker lock(DUChain::lock()); enumeratorType->setDeclaration(decl); decl->setAbstractType(enumeratorType.cast()); } } void DeclarationBuilder::visitConstructorDeclaration(ConstructorDeclarationAst * node) { openDefinition(node->className, node); DeclarationBuilderBase::visitConstructorDeclaration(node); closeDeclaration(); } void DeclarationBuilder::visitMethodDeclaration(MethodDeclarationAst * node) { ClassFunctionDeclaration* newMethod = openDefinition(node->methodName, node); newMethod->setAccessPolicy(parseAccessPolicy(node->modifiers)); - newMethod->setStorageSpecifiers(parseModifiers(node->modifiers)); + newMethod->setStorageSpecifiers(ClassMemberDeclaration::StorageSpecifiers(static_cast(parseModifiers(node->modifiers)))); DeclarationBuilderBase::visitMethodDeclaration(node); closeDeclaration(); } void DeclarationBuilder::visitVariableDeclarationData(java::VariableDeclarationDataAst* node) { m_currentVariableModifiers = parseModifiers(node->modifiers); DeclarationBuilderBase::visitVariableDeclarationData(node); m_currentVariableModifiers = 0; } void DeclarationBuilder::visitVariableDeclarator(VariableDeclaratorAst * node) { if (currentContext()->type() == DUContext::Class) { ClassMemberDeclaration* classMember = openDefinition(node->variableName, node); - classMember->setStorageSpecifiers(m_currentVariableModifiers); + classMember->setStorageSpecifiers(ClassMemberDeclaration::StorageSpecifiers(static_cast(m_currentVariableModifiers))); classMember->setKind(Declaration::Instance); classMember->setAbstractType(lastType()); } else { Declaration* variableDeclaration = openDefinition(node->variableName, node); variableDeclaration->setKind(Declaration::Instance); variableDeclaration->setAbstractType(lastType()); #if 0 // Porting -- Declaration::final property got removed variableDeclaration->setFinal(m_currentVariableModifiers & ClassMemberDeclaration::FinalSpecifier); #endif } DeclarationBuilderBase::visitVariableDeclarator(node); closeDeclaration(); } void DeclarationBuilder::visitParameterDeclaration(ParameterDeclarationAst * node) { Declaration* parameter = openDefinition(node->variableName, node); parameter->setKind(Declaration::Instance); parameter->setAbstractType(lastType()); #if 0 // Porting -- Declaration::final property got removed parameter->setFinal(node->parameterModifiers ? node->parameterModifiers->modifiers & ModifierFinal : false); #endif DeclarationBuilderBase::visitParameterDeclaration(node); closeDeclaration(); } void DeclarationBuilder::visitParameterDeclarationEllipsis(ParameterDeclarationEllipsisAst * node) { Declaration* parameter = openDefinition(node->variableName, node); parameter->setKind(Declaration::Instance); parameter->setAbstractType(lastType()); #if 0 // Porting -- Declaration::final property got removed parameter->setFinal(node->parameterModifiers ? node->parameterModifiers->hasModifierFinal : false); #endif DeclarationBuilderBase::visitParameterDeclarationEllipsis(node); closeDeclaration(); } void DeclarationBuilder::visitImportDeclaration(ImportDeclarationAst* node) { if (!m_defaultImportCreated) { Q_ASSERT(javaLang.count() == 3); DUChainWriteLocker lock(DUChain::lock()); - NamespaceAliasDeclaration* decl = openDeclaration(QualifiedIdentifier(globalImportIdentifier()), RangeInRevision()); + NamespaceAliasDeclaration* decl = openDeclaration(globalImportIdentifier(), RangeInRevision()); decl->setImportIdentifier(javaLang); decl->setKind(Declaration::Import); closeDeclaration(); m_defaultImportCreated = true; } if (node && node->identifierName && node->identifierName->nameSequence) { QualifiedIdentifier import = identifierForNode(node->identifierName->nameSequence); if (node->identifierName->hasStar) { // Ignore imports of the current package, it's auto-imported. { DUChainReadLocker lock(DUChain::lock()); if (import == currentContext()->localScopeIdentifier()) return; } import.push(Identifier("*")); // Ignore imports of java.lang.*, it's auto-imported. if (import == javaLang) return; } ///@todo only use the last name component as range { DUChainWriteLocker lock(DUChain::lock()); - NamespaceAliasDeclaration* decl = openDeclaration(QualifiedIdentifier(node->staticImport ? Identifier(globalStaticImportIdentifier) : globalImportIdentifier()), editorFindRange(node->identifierName, node->identifierName)); + NamespaceAliasDeclaration* decl = openDeclaration(node->staticImport ? Identifier(globalStaticImportIdentifier) : globalImportIdentifier(), editorFindRange(node->identifierName, node->identifierName)); decl->setImportIdentifier(import); } closeDeclaration(); } } void DeclarationBuilder::visitPackageDeclaration(java::PackageDeclarationAst* node) { if (node && node->packageName) { // Use this to import other items from the package QualifiedIdentifier id = identifierForNode(node->packageName); KDevelop::RangeInRevision range = editorFindRange(node->packageName, node->packageName); { DUChainWriteLocker lock(DUChain::lock()); - NamespaceAliasDeclaration* decl = openDeclaration(QualifiedIdentifier(globalImportIdentifier()), range); + NamespaceAliasDeclaration* decl = openDeclaration(globalImportIdentifier(), range); QualifiedIdentifier id2 = id; id2.push(Identifier("*")); decl->setImportIdentifier(id2); decl->setContext(currentContext()->topContext()); decl->setKind(Declaration::NamespaceAlias); closeDeclaration(); // Some crazy issue with just passing the whole QI? - openDeclaration(QualifiedIdentifier(id.last()), range); + openDeclaration(id.last(), range); } DeclarationBuilderBase::visitPackageDeclaration(node); DUChainWriteLocker lock(DUChain::lock()); currentDeclaration()->setKind(KDevelop::Declaration::Namespace); closeDeclaration(); } } Declaration::AccessPolicy DeclarationBuilder::parseAccessPolicy(java::OptionalModifiersAst* node) { if (node) { if (node->modifiers & ModifierPublic) return Declaration::Public; if (node->modifiers & ModifierProtected) return Declaration::Protected; if (node->modifiers & ModifierPrivate) return Declaration::Private; } return Declaration::DefaultAccess; } -ClassMemberDeclaration::StorageSpecifiers DeclarationBuilder::parseModifiers(java::OptionalModifiersAst* node) +ClassDeclaration::StorageSpecifiers DeclarationBuilder::parseModifiers(java::OptionalModifiersAst* node) { - ClassMemberDeclaration::StorageSpecifiers ret; + ClassDeclaration::StorageSpecifiers ret; if (node) { if (node->modifiers & ModifierFinal) - ret |= ClassMemberDeclaration::FinalSpecifier; + ret |= ClassDeclaration::FinalSpecifier; if (node->modifiers & ModifierAbstract) - ret |= ClassMemberDeclaration::AbstractSpecifier; + ret |= ClassDeclaration::AbstractSpecifier; if (node->modifiers & ModifierStrictFP) - ret |= ClassMemberDeclaration::StrictFPSpecifier; + ret |= ClassDeclaration::StrictFPSpecifier; if (node->modifiers & ModifierSynchronized) - ret |= ClassMemberDeclaration::SynchronizedSpecifier; + ret |= ClassDeclaration::SynchronizedSpecifier; if (node->modifiers & ModifierStatic) - ret |= ClassMemberDeclaration::StaticSpecifier; + ret |= ClassDeclaration::StaticSpecifier; if (node->modifiers & ModifierNative) - ret |= ClassMemberDeclaration::NativeSpecifier; + ret |= ClassDeclaration::NativeSpecifier; //ModifierTransient = 1 << 4, //ModifierVolatile = 1 << 9, } return ret; } void DeclarationBuilder::classTypeOpened(AbstractType::Ptr type) { //We override this so we can get the class-declaration into a usable state(with filled type) earlier DUChainWriteLocker lock(DUChain::lock()); - IdentifiedType* idType = dynamic_cast(type.unsafeData()); + IdentifiedType* idType = dynamic_cast(type.data()); if( idType && !idType->declarationId().isValid() ) //When the given type has no declaration yet, assume we are declaring it now idType->setDeclaration( currentDeclaration() ); currentDeclaration()->setType(type); } } diff --git a/duchain/declarationbuilder.h b/duchain/declarationbuilder.h index 75b99cd..9c96232 100644 --- a/duchain/declarationbuilder.h +++ b/duchain/declarationbuilder.h @@ -1,76 +1,76 @@ /* This file is part of KDevelop Copyright 2006-2008 Hamish Rodda 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. */ #ifndef DECLARATIONBUILDER_H #define DECLARATIONBUILDER_H #include "typebuilder.h" #include -#include "javaduchainexport.h" +#include "javaduchain_export.h" namespace java { class ParseSession; typedef KDevelop::AbstractDeclarationBuilder DeclarationBuilderBase; /** * A class which iterates the AST to extract definitions of types. */ class KDEVJAVADUCHAIN_EXPORT DeclarationBuilder: public DeclarationBuilderBase { public: DeclarationBuilder(EditorIntegrator* editor); protected: virtual void closeDeclaration(); virtual void classContextOpened(KDevelop::DUContext* context); virtual void classTypeOpened(KDevelop::AbstractType::Ptr type); virtual void visitClassDeclaration(ClassDeclarationAst *node); virtual void visitClassExtendsClause(java::ClassExtendsClauseAst* node); virtual void visitImplementsClause(java::ImplementsClauseAst* node); virtual void visitClassOrInterfaceTypeName(ClassOrInterfaceTypeNameAst *node); virtual void visitMethodDeclaration(MethodDeclarationAst *node); virtual void visitInterfaceMethodDeclaration(InterfaceMethodDeclarationAst *node); virtual void visitConstructorDeclaration(ConstructorDeclarationAst *node); virtual void visitInterfaceDeclaration(InterfaceDeclarationAst *node); virtual void visitImportDeclaration(ImportDeclarationAst *node); virtual void visitVariableDeclarationData(VariableDeclarationDataAst *node); virtual void visitVariableDeclarator(VariableDeclaratorAst *node); virtual void visitParameterDeclaration(ParameterDeclarationAst *node); virtual void visitParameterDeclarationEllipsis(ParameterDeclarationEllipsisAst *node); virtual void visitPackageDeclaration(PackageDeclarationAst* node); virtual void visitEnumDeclaration(java::EnumDeclarationAst* node); virtual void visitEnumConstant(java::EnumConstantAst* node); KDevelop::Declaration::AccessPolicy parseAccessPolicy(OptionalModifiersAst* node); - KDevelop::ClassMemberDeclaration::StorageSpecifiers parseModifiers(OptionalModifiersAst* node); + ClassDeclaration::StorageSpecifiers parseModifiers(OptionalModifiersAst* node); private: bool m_defaultImportCreated; bool m_inImplementsClause; KDevelop::QualifiedIdentifier javaLang; - KDevelop::ClassMemberDeclaration::StorageSpecifiers m_currentVariableModifiers; + ClassDeclaration::StorageSpecifiers m_currentVariableModifiers; }; } #endif // DECLARATIONBUILDER_H diff --git a/duchain/dumpchain.cpp b/duchain/dumpchain.cpp index 46a9c4e..70dc1f9 100644 --- a/duchain/dumpchain.cpp +++ b/duchain/dumpchain.cpp @@ -1,269 +1,269 @@ /* This file is part of KDevelop Copyright 2002-2005 Roberto Raggi Copyright 2006-2008 Hamish Rodda 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. */ #include "dumpchain.h" #include #include +#include -#include #include #include #include "editorintegrator.h" #include #include #include #include #include #include #include #include "parsesession.h" using namespace KDevelop; using namespace java; static char const * const names[] = { "AdditiveExpression", "AdditiveExpressionRest", "Annotation", "AnnotationArguments", "AnnotationElementArrayInitializer", "AnnotationElementArrayValue", "AnnotationElementValue", "AnnotationElementValuePair", "AnnotationMethodDeclaration", "AnnotationTypeBody", "AnnotationTypeDeclaration", "AnnotationTypeField", "ArrayAccess", "ArrayCreatorRest", "ArrayTypeDotClass", "AssertStatement", "BitAndExpression", "BitOrExpression", "BitXorExpression", "Block", "BlockStatement", "BreakStatement", "BuiltInType", "BuiltInTypeDotClass", "CastExpression", "CatchClause", "ClassAccessBata", "ClassBody", "ClassDeclaration", "ClassExtendsClause", "ClassField", "ClassOrInterfaceTypeName", "ClassOrInterfaceTypeNamePart", "ClassType", "CompilationUnit", "ConditionalExpression", "ConstructorDeclaration", "ContinueStatement", "DoWhileStatement", "EmbeddedStatement", "EnumBody", "EnumConstant", "EnumConstantBody", "EnumConstantField", "EnumDeclaration", "EqualityExpression", "EqualityExpressionRest", "Expression", "ForClauseTraditionalRest", "ForControl", "ForStatement", "ForeachDeclarationData", "Identifier", "IfStatement", "ImplementsClause", "ImportDeclaration", "InterfaceBody", "InterfaceDeclaration", "InterfaceExtendsClause", "InterfaceField", "InterfaceMethodDeclaration", "LabeledStatement", "Literal", "LogicalAndExpression", "LogicalOrExpression", "MandatoryArrayBuiltInType", "MandatoryDeclaratorBrackets", "MethodCallData", "MethodDeclaration", "MultiplicativeExpression", "MultiplicativeExpressionRest", "NewExpression", "NonArrayType", "NonWildcardTypeArguments", "OptionalArgumentList", "OptionalArrayBuiltInType", "OptionalDeclaratorBrackets", "OptionalModifiers", "OptionalParameterDeclarationList", "OptionalParameterModifiers", "PackageDeclaration", "ParameterDeclaration", "ParameterDeclarationEllipsis", "PostfixOperator", "PrimaryAtom", "PrimaryExpression", "PrimarySelector", "QualifiedIdentifier", "QualifiedIdentifierWithOptionalStar", "RelationalExpression", "RelationalExpressionRest", "ReturnStatement", "ShiftExpression", "ShiftExpressionRest", "SimpleNameAccessData", "StatementExpression", "SuperAccessData", "SuperSuffix", "SwitchLabel", "SwitchSection", "SwitchStatement", "SynchronizedStatement", "ThisAccessData", "ThisCallData", "ThrowStatement", "ThrowsClause", "TryStatement", "Type", "TypeArgument", "TypeArgumentType", "TypeArguments", "TypeArgumentsOrParametersEnd", "TypeDeclaration", "TypeParameter", "TypeParameters", "UnaryExpression", "UnaryExpressionNotPlusMinus", "VariableArrayInitializer", "VariableDeclaration", "VariableDeclarationData", "VariableDeclarationRest", "VariableDeclarationSplitData", "VariableDeclarationStatement", "VariableDeclarator", "VariableInitializer", "WhileStatement", "WildcardType", "WildcardTypeBounds" }; DumpChain::DumpChain() : m_editor(0) , indent(0) { } void DumpChain::dump( AstNode * node, ParseSession* session) { delete m_editor; m_editor = 0; Q_ASSERT(session); m_session = session; m_editor = new EditorIntegrator(session); visitNode(node); } void DumpChain::visitNode(AstNode *node) { QString indentation; for( int a = 0; a < indent; a++ ) indentation += "| "; if (node) { if (m_editor) { QString nodeText; for( qint64 a = node->startToken; a <= node->endToken; a++ ) { if( !nodeText.isEmpty() ) nodeText += ' '; nodeText += m_session->symbol(a); } if( !nodeText.isEmpty() ) nodeText = "\"" + nodeText + "\""; - kDebug() << indentation << "\\" << names[node->kind - 1000] + qDebug() << indentation << "\\" << names[node->kind - 1000] << "[" << node->startToken << m_editor->findPosition(node->startToken, EditorIntegrator::FrontEdge) << ", " << node->endToken << m_editor->findPosition(node->endToken, EditorIntegrator::BackEdge) << "]" << nodeText << endl; } else { - kDebug() << indentation << "\\" << names[node->kind - 1000] + qDebug() << indentation << "\\" << names[node->kind - 1000] << "[" << node->startToken << "," << node->endToken << "]" << endl; } } ++indent; DefaultVisitor::visitNode(node); --indent; if (node) { if (m_editor) { - kDebug() << indentation << "/" << names[node->kind - 1000] + qDebug() << indentation << "/" << names[node->kind - 1000] << "[(" << node->endToken << ") "/*<< m_editor->findPosition(node->startToken, EditorIntegrator::FrontEdge) << ", "*/ << m_editor->findPosition(node->endToken, EditorIntegrator::FrontEdge) << "]" << endl; } else { - kDebug() << indentation << "/" << names[node->kind - 1000] + qDebug() << indentation << "/" << names[node->kind - 1000] << "[" << node->startToken << "," << node->endToken << ']' << endl; } } } DumpChain::~ DumpChain( ) { delete m_editor; } void DumpChain::dump( DUContext * context, bool imported ) { - kDebug() << QString(indent * 2, ' ') << (imported ? "==import==> Context " : "New Context ") << context << "\"" << context->localScopeIdentifier() << "\" [" << context->scopeIdentifier() << "]" << context->range() << " " << (dynamic_cast(context) ? "top-context" : ""); + qDebug() << QString(indent * 2, ' ') << (imported ? "==import==> Context " : "New Context ") << context << "\"" << context->localScopeIdentifier() << "\" [" << context->scopeIdentifier() << "]" << context->range() << " " << (dynamic_cast(context) ? "top-context" : ""); if( !context ) return; if (!imported) { foreach (Declaration* dec, context->localDeclarations()) { - kDebug() << QString((indent+1) * 2, ' ') << "Declaration: " << dec->toString() << /*(idType ? (" (type-identity: " + idType->identifier().toString() + ")") : QString()) <<*/ " [" << dec->qualifiedIdentifier() << "]" << dec << "(internal ctx" << dec->internalContext() << ")" << dec->range() << "," << (dec->isDefinition() ? "definition, " : "declaration, ") << dec->uses().count() << "use(s)," << (dec->inSymbolTable() ? " in symbol table" : " not in symbol table"); - QMap > uses = dec->uses(); - for(QMap >::const_iterator it = uses.begin(); it != uses.end(); ++it) { - kDebug() << QString((indent+2) * 2, ' ') << "File:" << it.key().str(); + qDebug() << QString((indent+1) * 2, ' ') << "Declaration: " << dec->toString() << /*(idType ? (" (type-identity: " + idType->identifier().toString() + ")") : QString()) <<*/ " [" << dec->qualifiedIdentifier() << "]" << dec << "(internal ctx" << dec->internalContext() << ")" << dec->range() << "," << (dec->isDefinition() ? "definition, " : "declaration, ") << dec->uses().count() << "use(s)," << (dec->inSymbolTable() ? " in symbol table" : " not in symbol table"); + QMap > uses = dec->uses(); + for(QMap >::const_iterator it = uses.begin(); it != uses.end(); ++it) { + qDebug() << QString((indent+2) * 2, ' ') << "File:" << it.key().str(); foreach (const RangeInRevision& range, *it) - kDebug() << QString((indent+2) * 2+1, ' ') << "Use:" << range; + qDebug() << QString((indent+2) * 2+1, ' ') << "Use:" << range; } } } ++indent; if (!imported) { ///@todo Think whether this is used for top-contexts, and if it is, prevent endless recursion due to loops foreach (const DUContext::Import& parent, context->importedParentContexts()) { dump(parent.context(context->topContext()), true); } foreach (DUContext* child, context->childContexts()) dump(child); } --indent; } diff --git a/duchain/dumpchain.h b/duchain/dumpchain.h index 672311e..db8cf00 100644 --- a/duchain/dumpchain.h +++ b/duchain/dumpchain.h @@ -1,59 +1,59 @@ /* This file is part of KDevelop Copyright 2002-2005 Roberto Raggi Copyright 2006-2008 Hamish Rodda 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. */ #ifndef DUMPCHAIN_H #define DUMPCHAIN_H #include "javadefaultvisitor.h" -#include "javaduchainexport.h" +#include "javaduchain_export.h" namespace KDevelop { class DUContext; } namespace java { class ParseSession; class KDEVJAVADUCHAIN_EXPORT DumpChain: protected DefaultVisitor { public: DumpChain(); virtual ~DumpChain(); void dump(AstNode *node, ParseSession* session = 0); void dump(KDevelop::DUContext* context, bool imported = false); protected: virtual void visitNode(java::AstNode *node); private: class EditorIntegrator* m_editor; ParseSession* m_session; int indent; }; } #endif // DUMPCHAIN_H diff --git a/duchain/editorintegrator.cpp b/duchain/editorintegrator.cpp index 33487a0..1985bc2 100644 --- a/duchain/editorintegrator.cpp +++ b/duchain/editorintegrator.cpp @@ -1,82 +1,79 @@ /* This file is part of KDevelop Copyright 2006 Hamish Rodda 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. */ #include "editorintegrator.h" #include -#include -#include - #include #include "javaast.h" #include "parsesession.h" using namespace KTextEditor; using namespace java; EditorIntegrator::EditorIntegrator( ParseSession* session ) : m_session(session) { } KDevelop::CursorInRevision EditorIntegrator::findPosition( qint64 token, Edge edge ) const { const KDevPG::TokenStream::Token& t = m_session->tokenStream->at(token); return findPosition(t, edge); } KDevelop::CursorInRevision EditorIntegrator::findPosition( const KDevPG::TokenStream::Token & token, Edge edge ) const { if(edge == BackEdge) return m_session->positionAt(token.end); else return m_session->positionAt(token.begin); } KDevelop::RangeInRevision EditorIntegrator::findRange( AstNode * node, RangeEdge edge ) { Q_UNUSED(edge); return KDevelop::RangeInRevision(findPosition(node->startToken, FrontEdge), findPosition(node->endToken, BackEdge)); } KDevelop::RangeInRevision EditorIntegrator::findRange( qint64 startToken, qint64 endToken ) { return KDevelop::RangeInRevision(findPosition(startToken, FrontEdge), findPosition(endToken, BackEdge)); } KDevelop::RangeInRevision EditorIntegrator::findRange(AstNode* from, AstNode* to) { return KDevelop::RangeInRevision(findPosition(from->startToken, FrontEdge), findPosition(to->endToken, BackEdge)); } KDevelop::RangeInRevision EditorIntegrator::findRange( const KDevPG::TokenStream::Token & token ) { return KDevelop::RangeInRevision(findPosition(token, FrontEdge), findPosition(token, BackEdge)); } QString EditorIntegrator::tokenToString(qint64 token) const { return m_session->symbol(token); } ParseSession * EditorIntegrator::parseSession() const { return m_session; } diff --git a/duchain/editorintegrator.h b/duchain/editorintegrator.h index b08508b..5f69107 100644 --- a/duchain/editorintegrator.h +++ b/duchain/editorintegrator.h @@ -1,133 +1,133 @@ /* This file is part of KDevelop Copyright 2006 Hamish Rodda 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. */ #ifndef JAVAEDITORINTEGRATOR_H #define JAVAEDITORINTEGRATOR_H #include #include "kdev-pg-token-stream.h" -#include "javaduchainexport.h" +#include "javaduchain_export.h" namespace java { class ParseSession; class AstNode; /** * Provides facilities for easy integration of a text editor component with * the information parsed from a source file. * * Uses a disguised singleton + stateful design. * * \todo introduce stacks for the state? */ class KDEVJAVADUCHAIN_EXPORT EditorIntegrator { public: EditorIntegrator(ParseSession* session); ParseSession* parseSession() const; enum Edge { FrontEdge, BackEdge }; enum RangeEdge { InnerEdge, OuterEdge }; /** * Finds the location and \a file where the given \a token was parsed from. This function * does not change any of the EditorIntegrator's state. * * \param token token to locate * \param edge set to FrontEdge to return the start position of the token, BackEdge to return the end position. * * \returns the requested cursor relating to the start or end of the given token. */ KDevelop::CursorInRevision findPosition(const KDevPG::TokenStream::Token& token, Edge edge = BackEdge) const; /** * Finds the location and \a file where the given \a token was parsed from. * This function does not change any of the EditorIntegrator's state. * * \param token token to locate * \param edge set to FrontEdge to return the start position of the token, BackEdge to return the end position. * * \returns the requested cursor relating to the start or end of the given token. */ KDevelop::CursorInRevision findPosition(qint64 token, Edge edge = BackEdge) const; /** * Create a range encompassing the given AstNode \a node. * This function does not change any of the EditorIntegrator's state. * * \overload */ KDevelop::RangeInRevision findRange(AstNode* node, RangeEdge = OuterEdge); /** * Create a range encompassing the given AstNode \a nodes. * This function does not change any of the EditorIntegrator's state. * * \overload */ KDevelop::RangeInRevision findRange(AstNode* from, AstNode* to); /** * Create a range encompassing the given AstNode \a token. * This function does not change any of the EditorIntegrator's state. * * \overload */ KDevelop::RangeInRevision findRange(const KDevPG::TokenStream::Token& token); /** * Create a range encompassing the given AstNode \a token. * This function does not change any of the EditorIntegrator's state. * * \overload */ KDevelop::RangeInRevision findRange(qint64 token); /** * Create a range encompassing the given AstNode \a tokens. * This function does not change any of the EditorIntegrator's state. * * \overload */ KDevelop::RangeInRevision findRange(qint64 start_token, qint64 end_token); /** * Retrieve the string represented by a token. */ QString tokenToString(qint64 token) const; private: ParseSession* m_session; }; } #endif // JAVAEDITORINTEGRATOR_H diff --git a/duchain/expressionvisitor.cpp b/duchain/expressionvisitor.cpp index 259b0bd..d2592b3 100644 --- a/duchain/expressionvisitor.cpp +++ b/duchain/expressionvisitor.cpp @@ -1,368 +1,368 @@ /* Copyright 2009 Hamish Rodda 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. */ #include "expressionvisitor.h" #include #include "overloadresolver.h" #include "editorintegrator.h" #include using namespace KDevelop; namespace java { ExpressionVisitor::ExpressionVisitor(EditorIntegrator* editor) { m_editor = editor; } void ExpressionVisitor::visitBuiltInType(BuiltInTypeAst* node) { IntegralType::CommonIntegralTypes type = IntegralType::TypeNone; switch (node->type) { case BuiltInTypeVoid: type = IntegralType::TypeVoid; break; case BuiltInTypeBoolean: type = IntegralType::TypeBoolean; break; case BuiltInTypeByte: type = IntegralType::TypeByte; break; case BuiltInTypeChar: type = IntegralType::TypeChar; break; case BuiltInTypeShort: type = IntegralType::TypeShort; break; case BuiltInTypeInt: type = IntegralType::TypeInt; break; case BuiltInTypeFloat: type = IntegralType::TypeFloat; break; case BuiltInTypeLong: type = IntegralType::TypeLong; break; case BuiltInTypeDouble: type = IntegralType::TypeDouble; break; } setLastType(IntegralType::Ptr(new IntegralType(type))); } void ExpressionVisitor::visitClassOrInterfaceTypeName(ClassOrInterfaceTypeNameAst* node) { QualifiedIdentifier id; if (node->partSequence) { auto it = node->partSequence->front(), end = it; do { QString ident = editor()->parseSession()->symbol(it->element->identifier->ident); id.push(Identifier(ident)); it = it->next; } while (it != end); } DeclarationPointer useDecl; AstNode* useNode = 0; AbstractType::Ptr type = openTypeFromName(id, true); if (StructureType::Ptr classType = StructureType::Ptr::dynamicCast(type)) { DUChainReadLocker lock(DUChain::lock()); useDecl = classType->declaration(topContext()); if (useDecl) useNode = node; else - kDebug() << classType->toString() << "unable to return its declaration."; + qDebug() << classType->toString() << "unable to return its declaration."; } else { - kDebug() << id.toString() << "cannot be found as a class or interface type name."; + qDebug() << id.toString() << "cannot be found as a class or interface type name."; } if (useNode) usingDeclaration(useNode, useDecl); } AbstractType::Ptr ExpressionVisitor::openTypeFromName(QualifiedIdentifier id, bool needClass) { AbstractType::Ptr openedType; bool delay = false; if(!delay) { DUChainReadLocker lock(DUChain::lock()); QList dec = currentContext()->findDeclarations(id); if ( dec.isEmpty() ) delay = true; if(!delay) { foreach( Declaration* decl, dec ) { // gcc 4.0.1 doesn't eath this // if( needClass && !decl->abstractType().cast() ) if( needClass && !decl->abstractType().cast(static_cast(0)) ) continue; if (decl->abstractType() ) { ///@todo only functions may have multiple declarations here - //ifDebug( if( dec.count() > 1 ) kDebug() << id.toString() << "was found" << dec.count() << "times" ) - //kDebug() << "found for" << id.toString() << ":" << decl->toString() << "type:" << decl->abstractType()->toString() << "context:" << decl->context(); + //ifDebug( if( dec.count() > 1 ) qDebug() << id.toString() << "was found" << dec.count() << "times" ) + //qDebug() << "found for" << id.toString() << ":" << decl->toString() << "type:" << decl->abstractType()->toString() << "context:" << decl->context(); openedType = decl->abstractType(); setLastType(decl->abstractType()); break; } } } if(!openedType) delay = true; } ///@todo What about position? return openedType; } void ExpressionVisitor::visitLiteral(LiteralAst* node) { ConstantIntegralType::Ptr newConstant; switch (node->literalType) { case LiteralInteger: { newConstant = new ConstantIntegralType(IntegralType::TypeInt); newConstant->setValue(node->integerLiteral); break; } case LiteralCharacter: { newConstant = new ConstantIntegralType(IntegralType::TypeChar); newConstant->setValue(node->characterLiteral); break; } case LiteralFloatingPoint: { newConstant = new ConstantIntegralType(IntegralType::TypeFloat); newConstant->setValue(node->floatingPointLiteral); break; } case LiteralString: { QualifiedIdentifier string; string.push(Identifier("java")); string.push(Identifier("lang")); string.push(Identifier("String")); openTypeFromName(string, true); return; } case LiteralTrue: case LiteralFalse:{ newConstant = new ConstantIntegralType(IntegralType::TypeBoolean); newConstant->setValue(node->literalType == LiteralTrue); break; } case LiteralNull: newConstant = ConstantIntegralType::Ptr(new ConstantIntegralType(IntegralType::TypeNull)); break; default: return; } setLastType(newConstant); } void ExpressionVisitor::visitMethodCallData(MethodCallDataAst* node) { DeclarationPointer useDecl; AstNode* useNode = 0; if (lastInstance().declaration) { if (node->methodName) { QualifiedIdentifier id (editor()->parseSession()->symbol(node->methodName->ident)); DUContextPointer searchContext; { DUChainReadLocker lock(DUChain::lock()); StructureType::Ptr classType = lastInstance().declaration->type(); if (!classType) { - kDebug() << "Type of last instance " << lastInstance().declaration->toString() << "was not a structure."; + qDebug() << "Type of last instance " << lastInstance().declaration->toString() << "was not a structure."; return; } searchContext = classType->internalContext(topContext()); if (!searchContext) { - kDebug() << "could not find internal context for the structure type of the class to be searched"; + qDebug() << "could not find internal context for the structure type of the class to be searched"; return; } - kDebug() << "Looking for function" << id << "in" << searchContext->scopeIdentifier(true); + qDebug() << "Looking for function" << id << "in" << searchContext->scopeIdentifier(true); } QList parameters; if (node->arguments && node->arguments->expressionSequence) { const KDevPG::ListNode *__it = node->arguments->expressionSequence->front(), *__end = __it; do { visitNode(__it->element); // TODO determine l-value-ness if required if (lastType()) { - kDebug() << "Parameter" << lastType()->toString(); + qDebug() << "Parameter" << lastType()->toString(); parameters.append(OverloadResolver::Parameter(lastType(), false)); } __it = __it->next; } while (__it != __end); } DUChainReadLocker lock(DUChain::lock()); OverloadResolver resolver(searchContext); - //kDebug() << "Parameter count:" << parameters.count(); + //qDebug() << "Parameter count:" << parameters.count(); useDecl = resolver.resolve(OverloadResolver::ParameterList(parameters), id); if (useDecl) useNode = node->methodName; - kDebug() << "result" << (useDecl ? useDecl->toString() : "null declaration") << useNode; + qDebug() << "result" << (useDecl ? useDecl->toString() : "null declaration") << useNode; } if (useNode) usingDeclaration(useNode, useDecl); } else { - kDebug() << "No declaration for the last instance on which to invoke a method"; + qDebug() << "No declaration for the last instance on which to invoke a method"; } } void ExpressionVisitor::visitNewExpression(NewExpressionAst* node) { ExpressionVisitorBase::visitNewExpression(node); if (lastType()) setInstantiatedType(true); } void ExpressionVisitor::visitOptionalArrayBuiltInType(OptionalArrayBuiltInTypeAst* node) { if (!node->type) return; visitBuiltInType(node->type); if (node->declaratorBrackets) { ArrayType::Ptr newArrayType(new ArrayType()); newArrayType->setDimension(node->declaratorBrackets->bracketCount); newArrayType->setElementType(lastType()); setLastType(newArrayType); } } void ExpressionVisitor::visitPrimaryAtom(PrimaryAtomAst* node) { ExpressionVisitorBase::visitPrimaryAtom(node); DeclarationPointer useDecl; AstNode* useNode = 0; if (node->simpleNameAccess && node->simpleNameAccess->name) { QualifiedIdentifier id (editor()->parseSession()->symbol(node->simpleNameAccess->name->ident)); DUChainReadLocker lock(DUChain::lock()); CursorInRevision start = editor()->findRange(node, node).start; QList decls = currentContext()->findDeclarations(id, start); if (!decls.isEmpty()) { setLastInstance(decls.first()); useDecl = decls.first(); useNode = node->simpleNameAccess; } - //kDebug() << currentContext()->localScopeIdentifier().toString() << id << start << decls.count() << useDecl << useNode; + //qDebug() << currentContext()->localScopeIdentifier().toString() << id << start << decls.count() << useDecl << useNode; } if (node->superAccess) { DUChainReadLocker lock(DUChain::lock()); if (ClassDeclaration* decl = dynamic_cast(lastInstance().declaration.data())) { if (decl->baseClassesSize() >= 1) { if (StructureType::Ptr baseClass = decl->baseClasses()->baseClass.type()) { setLastType(decl->baseClasses()->baseClass.abstractType()); useDecl = baseClass->declaration(topContext()); useNode = node->superAccess; } } } } if (useNode) usingDeclaration(useNode, useDecl); } void ExpressionVisitor::visitPrimaryExpression(PrimaryExpressionAst* node) { ExpressionVisitorBase::visitPrimaryExpression(node); } void ExpressionVisitor::visitPrimarySelector(PrimarySelectorAst* node) { DeclarationPointer useDecl; AstNode* useNode = 0; if (lastInstance().isInstance) { DUChainReadLocker lock(DUChain::lock()); if (node->simpleNameAccess && node->simpleNameAccess->name) { QualifiedIdentifier id (editor()->parseSession()->symbol(node->simpleNameAccess->name->ident)); if (lastInstance().declaration) { DUContext* declContext = lastInstance().declaration->logicalInternalContext(topContext()); if (declContext) { foreach (Declaration* decl, declContext->findDeclarations(id)) { // Only select fields if (decl->abstractType() && !FunctionType::Ptr::dynamicCast(decl->abstractType())) { setLastInstance(decl); useNode = node->simpleNameAccess; useDecl = decl; break; } } } else { - kWarning() << "Internal context for declaration" << lastInstance().declaration->toString() << "was null."; + qWarning() << "Internal context for declaration" << lastInstance().declaration->toString() << "was null."; } } else { - kWarning() << "No last instance for primary selector at" << editor()->findRange(node->simpleNameAccess->name, node->simpleNameAccess->name); + qWarning() << "No last instance for primary selector at" << editor()->findRange(node->simpleNameAccess->name, node->simpleNameAccess->name); } } } if (node->thisAccess) { if (lastInstance().isInstance) { // Nothing to do - already the correct instance and type? } else { DUChainReadLocker lock(DUChain::lock()); setLastInstance(currentContext()->owner()); useNode = node->thisAccess; useDecl = currentContext()->owner(); } } if (node->methodCall) visitNode(node->methodCall); if (useNode) usingDeclaration(useNode, useDecl); } void ExpressionVisitor::visitNode(AstNode* node) { if(!node) return; PushPositiveValue pushContext(m_currentContext, node->ducontext); Visitor::visitNode(node); } } diff --git a/duchain/helpers.h b/duchain/helpers.h index 408bd98..add99a6 100644 --- a/duchain/helpers.h +++ b/duchain/helpers.h @@ -1,34 +1,34 @@ #ifndef KDEVJAVA_HELPERS_H #define KDEVJAVA_HELPERS_H #include #include #include -#include +#include using namespace KDevelop; namespace java { static KDevelop::ReferencedTopDUContext allJavaContext() { - static IndexedString global(KUrl("java://all")); + static IndexedString global(QUrl("java://all")); DUChainReadLocker lock; ReferencedTopDUContext top = DUChain::self()->chainForDocument(global); if ( ! top ) { lock.unlock(); DUChainWriteLocker wlock; top = new KDevelop::TopDUContext(global, KDevelop::RangeInRevision()); top->setType( KDevelop::DUContext::Global ); KDevelop::DUChain::self()->addDocumentChain(top); } return top; } static QString globalStaticImportIdentifier; }; #endif // kate: space-indent on; indent-width 4 \ No newline at end of file diff --git a/duchain/identifiercompiler.cpp b/duchain/identifiercompiler.cpp index 548c963..a78d7b1 100644 --- a/duchain/identifiercompiler.cpp +++ b/duchain/identifiercompiler.cpp @@ -1,108 +1,106 @@ /* This file is part of KDevelop Copyright 2002-2005 Roberto Raggi Copyright 2006-2007 Hamish Rodda 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 "identifiercompiler.h" #include "javaast.h" #include "javaparser.h" #include "parsesession.h" //#include "tokens.h" -#include - using namespace KDevelop; using namespace java; /*QString decode(ParseSession* session, AST* ast, bool without_spaces = false) { QString ret; if( without_spaces ) { //Decode operator-names without spaces for now, since we rely on it in other places. ///@todo change this, here and in all the places that rely on it. Operators should then by written like "operator [ ]"(space between each token) for( size_t a = ast->start_token; a < ast->end_token; a++ ) { const Token &tk = session->tokenStream->token(a); ret += tk.symbol(); } } else { for( size_t a = ast->start_token; a < ast->end_token; a++ ) { const Token &tk = session->tokenStream->token(a); ret += tk.symbol() + " "; } } return ret; }*/ uint parseConstVolatile(ParseSession* session, const KDevPG::ListNode *cv) { uint ret = AbstractType::NoModifiers; if (cv) { const KDevPG::ListNode *it = cv->front(); const KDevPG::ListNode *end = it; do { int kind = session->tokenStream->at(it->element).kind; if (kind == Parser::Token_CONST) ret |= AbstractType::ConstModifier; else if (kind == Parser::Token_VOLATILE) ret |= AbstractType::VolatileModifier; it = it->next; } while (it != end); } return ret; } IdentifierCompiler::IdentifierCompiler(ParseSession* session) : m_session(session) { } void IdentifierCompiler::run(AstNode *node) { m_name.clear(); visitNode(node); } void IdentifierCompiler::visitIdentifier(IdentifierAst *node) { QString tmp_name; if (node->ident) tmp_name += m_session->symbol(node->ident); m_currentIdentifier = Identifier(m_session->unify(tmp_name)); m_name.push(m_currentIdentifier); } const QualifiedIdentifier& IdentifierCompiler::identifier() const { return m_name; } void IdentifierCompiler::visitQualifiedIdentifierWithOptionalStar(QualifiedIdentifierWithOptionalStarAst *node) { DefaultVisitor::visitQualifiedIdentifierWithOptionalStar(node); if (node->hasStar) { m_name.push(Identifier("*")); } } diff --git a/duchain/javaduchainexport.h b/duchain/javaduchainexport.h deleted file mode 100644 index 33ef791..0000000 --- a/duchain/javaduchainexport.h +++ /dev/null @@ -1,36 +0,0 @@ -/*************************************************************************** - * This file is part of KDevelop * - * Copyright 2014 Sven Brauch * - * * - * This program 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 program 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 General Public License for more details. * - * * - * You should have received a copy of the GNU Library General Public * - * License along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ - -#ifndef JAVADUCHAINEXPORT_H -#define JAVADUCHAINEXPORT_H - -/* needed for KDE_EXPORT macros */ -#include - -#ifndef KDEVJAVADUCHAIN_EXPORT -# ifdef MAKE_KDEVJAVADUCHAIN_LIB -# define KDEVJAVADUCHAIN_EXPORT KDE_EXPORT -# else -# define KDEVJAVADUCHAIN_EXPORT KDE_IMPORT -# endif -#endif - -#endif - diff --git a/duchain/overloadresolver.cpp b/duchain/overloadresolver.cpp index 49532ef..22c7b50 100644 --- a/duchain/overloadresolver.cpp +++ b/duchain/overloadresolver.cpp @@ -1,446 +1,446 @@ /* Copyright 2007 David Nolden Copyright 2009 Hamish Rodda 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. */ #include "overloadresolver.h" #include #include -#include +#include #include #include #include #include "typeconversion.h" #include "typeutils.h" #include "viablefunctions.h" namespace java { - + using namespace KDevelop; OverloadResolver::OverloadResolver( DUContextPointer context, bool forceIsInstance ) : m_context(context), m_topContext(context->topContext()), m_worstConversionRank(NoMatch), m_forceIsInstance(forceIsInstance) { } Declaration* OverloadResolver::resolveConstructor( const ParameterList& params, bool implicit, bool noUserDefinedConversion ) { if( !m_context || !m_topContext ) return 0; QList goodDeclarations; Identifier id = m_context->localScopeIdentifier().last(); id.clearTemplateIdentifiers(); QList declarations = m_context->findLocalDeclarations(id, KDevelop::CursorInRevision(), m_topContext.data(), AbstractType::Ptr(), DUContext::OnlyFunctions); for( QList::iterator it = declarations.begin(); it != declarations.end(); ++it ) { if( (*it)->indexedType() ) { FunctionType::Ptr function = (*it)->abstractType().cast(); ClassFunctionDeclaration* functionDeclaration = dynamic_cast(*it); //Q_ASSERT(); if( functionDeclaration /*&& functionDeclaration->isConstructor()*/ ) //Test not needed, because name == classname { if( function->indexedArgumentsSize() >= params.parameters.size() ) { if( !implicit || !functionDeclaration->isExplicit() ) goodDeclarations << *it; } } } } return resolveList( params, goodDeclarations, noUserDefinedConversion ); } Declaration* OverloadResolver::resolve( const ParameterList& params, const QualifiedIdentifier& functionName, bool noUserDefinedConversion ) { if( !m_context || !m_topContext ) return 0; QList declarations = m_context->findDeclarations(functionName, KDevelop::CursorInRevision(), AbstractType::Ptr(), m_topContext.data()); return resolveList(params, declarations, noUserDefinedConversion ); } uint OverloadResolver::worstConversionRank() { return m_worstConversionRank; } void OverloadResolver::expandDeclarations( const QList& declarations, QSet& newDeclarations ) { for( QList::const_iterator it = declarations.constBegin(); it != declarations.constEnd(); ++it ) { Declaration* decl = *it; bool isConstant = false; if( StructureType::Ptr klass = TypeUtils::realType(decl->abstractType(), m_topContext.data(), &isConstant).cast() ) { if( decl->kind() == Declaration::Instance || m_forceIsInstance ) { //Instances of classes should be substituted with their operator() members QList decls; TypeUtils::getMemberFunctions( klass, m_topContext.data(), decls, "operator()", isConstant ); foreach(Declaration* decl, decls) newDeclarations.insert(decl); } else { //Classes should be substituted with their constructors QList decls; TypeUtils::getConstructors( klass, m_topContext.data(), decls ); foreach(Declaration* decl, decls) newDeclarations.insert(decl); } }else{ newDeclarations.insert(*it); } } } void OverloadResolver::expandDeclarations( const QList >& declarations, QHash& newDeclarations ) { for( QList >::const_iterator it = declarations.constBegin(); it != declarations.constEnd(); ++it ) { QPair decl = *it; bool isConstant = false; if( StructureType::Ptr klass = TypeUtils::realType(decl.second->abstractType(), m_topContext.data(), &isConstant).cast() ) { if( decl.second->kind() == Declaration::Instance || m_forceIsInstance ) { //Instances of classes should be substituted with their operator() members QList functions; TypeUtils::getMemberFunctions( klass, m_topContext.data(), functions, "operator()", isConstant ); foreach(Declaration* f, functions) newDeclarations.insert(f, decl.first); } else { //Classes should be substituted with their constructors QList functions; TypeUtils::getConstructors( klass, m_topContext.data(), functions ); foreach(Declaration* f, functions) newDeclarations.insert(f, decl.first); } }else{ newDeclarations.insert(it->second, it->first); } } } Declaration* OverloadResolver::resolveList( const ParameterList& params, const QList& declarations, bool noUserDefinedConversion ) { if( !m_context || !m_topContext ) return 0; ///Iso c++ draft 13.3.3 m_worstConversionRank = ExactMatch; ///First step: Replace class-instances with operator() functions, and pure classes with their constructors QSet newDeclarations; expandDeclarations( declarations, newDeclarations ); ///Second step: Find best viable function ViableFunction bestViableFunction( m_topContext.data() ); for( QSet::const_iterator it = newDeclarations.constBegin(); it != newDeclarations.constEnd(); ++it ) { // TODO apply implicit template parameters Declaration* decl = *it; if( !decl ) continue; ViableFunction viable( m_topContext.data(), decl, noUserDefinedConversion ); viable.matchParameters( params ); if( viable.isBetter(bestViableFunction) ) { bestViableFunction = viable; m_worstConversionRank = bestViableFunction.worstConversion(); } } if( bestViableFunction.isViable() ) return bestViableFunction.declaration().data(); else return 0; } QList< ViableFunction > OverloadResolver::resolveListOffsetted( const ParameterList& params, const QList >& declarations, bool partial ) { if( !m_context || !m_topContext ) return QList(); ///Iso c++ draft 13.3.3 m_worstConversionRank = ExactMatch; ///First step: Replace class-instances with operator() functions, and pure classes with their constructors QHash newDeclarations; expandDeclarations( declarations, newDeclarations ); ///Second step: Find best viable function QList viableFunctions; for( QHash::const_iterator it = newDeclarations.constBegin(); it != newDeclarations.constEnd(); ++it ) { ViableFunction viable( m_topContext.data(), it.key() ); ParameterList mergedParams = it.value(); mergedParams.parameters += params.parameters; viable.matchParameters( mergedParams, partial ); viableFunctions << viable; } qSort( viableFunctions ); return viableFunctions; } /*Declaration* OverloadResolver::applyImplicitTemplateParameters( const ParameterList& params, Declaration* declaration ) const { TemplateDeclaration* tempDecl = dynamic_cast(declaration); if(!tempDecl) return declaration; KDevelop::DUContext* templateContext = tempDecl->templateParameterContext(); if(!templateContext) { //May be just within a template, but without own template parameters return declaration; } FunctionType::Ptr functionType = declaration->type(); if(!functionType) { - kDebug(9007) << "Template function has no function type"; + qDebug(9007) << "Template function has no function type"; return declaration; } const IndexedType* arguments( functionType->indexedArguments() ); if(params.parameters.count() > functionType->indexedArgumentsSize()) return declaration; //templateContext contains the template-parameters that we need to find instantiations for QMap instantiatedParameters; //Here we store the values assigned to each template-parameter foreach( Declaration* decl, templateContext->localDeclarations() ) { CppTemplateParameterType::Ptr paramType = decl->abstractType().cast(); if( paramType ) { //Parameters that are not of type CppTemplateParameterType are already assigned. instantiatedParameters[decl->identifier().identifier()] = AbstractType::Ptr(); } } if( instantiatedParameters.isEmpty() ) return declaration; //All parameters already have a type assigned for( int a = 0; a < params.parameters.count(); a++ ) matchParameterTypes(params.parameters[a].type, arguments[a].abstractType(), instantiatedParameters); bool allInstantiated = true; for( QMap::const_iterator it = instantiatedParameters.constBegin(); it != instantiatedParameters.constEnd(); ++it ) if( !(*it) ) { allInstantiated = false; } if( allInstantiated ) { //We have new template-parameters at hand, we can specialize now. Cpp::InstantiationInformation instantiateWith(tempDecl->instantiatedWith().information()); instantiateWith.templateParametersList().clear(); foreach( Declaration* decl, templateContext->localDeclarations() ) { AbstractType::Ptr type; CppTemplateParameterType::Ptr paramType = decl->abstractType().cast(); if( paramType ) //Take the type we have assigned. type = instantiatedParameters[decl->identifier().identifier()]; else type = decl->abstractType(); //Take the type that was available already earlier instantiateWith.addTemplateParameter(type); } Declaration* ret = tempDecl->instantiate( instantiateWith, m_topContext.data() ); ///@todo find out when can fail //Q_ASSERT(ret->id().getDeclaration(m_topContext.data()) == ret); return ret; } return declaration; }*/ inline uint incrementIfSuccessful(uint val) { if(val) return 1 + val; return 0; } #define ifDebugOverloadResolution(x) // #define ifDebugOverloadResolution(x) x uint OverloadResolver::matchParameterTypes(const AbstractType::Ptr& argumentType, const AbstractType::Ptr& parameterType, QMap& instantiatedTypes, bool keepValue) const { if(!argumentType && !parameterType) return 1; if(!argumentType || !parameterType) return 0; - - ifDebugOverloadResolution( kDebug() << "matching" << argumentType->toString() << "to" << parameterType->toString(); ) - + + ifDebugOverloadResolution( qDebug() << "matching" << argumentType->toString() << "to" << parameterType->toString(); ) + if(instantiatedTypes.isEmpty()) return 1; DelayedType::Ptr delayed = parameterType.cast(); if(delayed) return incrementIfSuccessful( matchParameterTypes( argumentType, delayed->identifier(), instantiatedTypes , keepValue) ); ///In case of references on both sides, match the target-types ReferenceType::Ptr argumentRef = argumentType.cast(); ReferenceType::Ptr parameterRef = parameterType.cast(); if( argumentRef && parameterRef ) return incrementIfSuccessful( matchParameterTypes( argumentRef->baseType(), parameterRef->baseType(), instantiatedTypes, keepValue ) ); else if(argumentRef) return incrementIfSuccessful( matchParameterTypes( argumentRef->baseType(), parameterType, instantiatedTypes, keepValue ) ); else if(parameterRef) return incrementIfSuccessful( matchParameterTypes( argumentType, parameterRef->baseType(), instantiatedTypes, keepValue ) ); ///In case of pointers on both sides, match the target-types PointerType::Ptr argumentPointer = argumentType.cast(); PointerType::Ptr parameterPointer = parameterType.cast(); if( argumentPointer && parameterPointer && ((argumentPointer->modifiers() & AbstractType::ConstModifier) == (parameterPointer->modifiers() & AbstractType::ConstModifier)) ) return incrementIfSuccessful( matchParameterTypes( argumentPointer->baseType(), parameterPointer->baseType(), instantiatedTypes, keepValue ) ); - + /*if(CppTemplateParameterType::Ptr templateParam = parameterType.cast()) { ///@todo Allow template-parameters with even more template-parameters declared //Directly assign argumentType to the template parameter Declaration* decl = templateParam->declaration(m_topContext.data()); if(decl) { IndexedString id = decl->identifier().identifier(); if(instantiatedTypes[id].isNull()) { instantiatedTypes[id] = argumentType; return 1; - }else if(instantiatedTypes[id]->equals(argumentType.unsafeData())) { + }else if(instantiatedTypes[id]->equals(argumentType.data())) { return 1; }else{ //Mismatch, another type was already assigned return 0; } } }*/ - + ///Match assigned template-parameters, for example when matching QList to QList, assign int to T. - const IdentifiedType* identifiedArgument = dynamic_cast(argumentType.unsafeData()); - const IdentifiedType* identifiedParameter = dynamic_cast(parameterType.unsafeData()); - + const IdentifiedType* identifiedArgument = dynamic_cast(argumentType.data()); + const IdentifiedType* identifiedParameter = dynamic_cast(parameterType.data()); + if( identifiedArgument && identifiedParameter ) { //TemplateDeclaration* argumentTemplateDeclaration = dynamic_cast(identifiedArgument->declaration(m_topContext.data())); //TemplateDeclaration* parameterTemplateDeclaration = dynamic_cast(identifiedParameter->declaration(m_topContext.data())); //if(!argumentTemplateDeclaration || !parameterTemplateDeclaration) return 1; - + /*if(argumentTemplateDeclaration->instantiatedFrom() == parameterTemplateDeclaration->instantiatedFrom() && argumentTemplateDeclaration->instantiatedFrom()) { InstantiationInformation argumentInstantiatedWith = argumentTemplateDeclaration->instantiatedWith().information(); InstantiationInformation parameterInstantiatedWith = parameterTemplateDeclaration->instantiatedWith().information(); - + if(argumentInstantiatedWith.templateParametersSize() != parameterInstantiatedWith.templateParametersSize()) return 0; - + uint matchDepth = 1; - + for(uint a = 0; a < argumentInstantiatedWith.templateParametersSize(); ++a) { uint localMatchDepth = matchParameterTypes(argumentInstantiatedWith.templateParameters()[a].abstractType(), parameterInstantiatedWith.templateParameters()[a].abstractType(), instantiatedTypes, keepValue); if(!localMatchDepth) return 0; matchDepth += localMatchDepth; } - + return matchDepth; }*/ } return 1; } AbstractType::Ptr getContainerType(AbstractType::Ptr type, int depth, TopDUContext* topContext) { for(int a = 0; a < depth; a++) { AbstractType::Ptr real = TypeUtils::realType(type, topContext); - IdentifiedType* idType = dynamic_cast(real.unsafeData()); + IdentifiedType* idType = dynamic_cast(real.data()); if(!idType) return AbstractType::Ptr(); Declaration* decl = idType->declaration(topContext); Declaration* containerDecl = decl->context()->owner(); if(containerDecl) type = containerDecl->abstractType(); else return AbstractType::Ptr(); } return type; } uint OverloadResolver::matchParameterTypes(AbstractType::Ptr argumentType, const IndexedTypeIdentifier& parameterType, QMap& instantiatedTypes, bool keepValue) const { - ifDebugOverloadResolution( kDebug() << "1 matching" << argumentType->toString() << "to" << parameterType.toString() << parameterType.pointerDepth(); ) + ifDebugOverloadResolution( qDebug() << "1 matching" << argumentType->toString() << "to" << parameterType.toString() << parameterType.pointerDepth(); ) if(!argumentType) return 1; if(instantiatedTypes.isEmpty()) return 1; - + QualifiedIdentifier parameterQid(parameterType.identifier().identifier()); - + if(parameterQid.isEmpty()) return 1; { ReferenceType::Ptr argumentRef = argumentType.cast(); if( argumentRef && parameterType.isReference() ) argumentType = argumentRef->baseType(); else if( parameterType.isReference() ) return 0; //Reference on right side, but not on left } { PointerType::Ptr argumentPointer = argumentType.cast(); int cnt = 0; ///@todo correct ordering of the pointers and their constnesses while( argumentPointer && cnt < parameterType.pointerDepth() ) { ++cnt; argumentType = argumentPointer->baseType(); argumentPointer = argumentType.cast(); } if( cnt != parameterType.pointerDepth() || !argumentType ) { return 0; //Do not have the needed count of pointers } } uint matchDepth = 1; if((argumentType->modifiers() & AbstractType::ConstModifier) && parameterType.isConstant()) ++matchDepth; #if 0 for( int a = 0; a < parameterQid.count(); ++a ) { ///@todo Think about this AbstractType::Ptr pType = getContainerType(argumentType, parameterQid.count() - a - 1, m_topContext.data()); uint localDepth = matchParameterTypes(pType, parameterQid.at(a), instantiatedTypes, keepValue); // if(!localDepth) // return 0; matchDepth += localDepth; } #endif - + return matchDepth; } } diff --git a/duchain/tests/CMakeLists.txt b/duchain/tests/CMakeLists.txt index cd2bd7b..0ff5e52 100644 --- a/duchain/tests/CMakeLists.txt +++ b/duchain/tests/CMakeLists.txt @@ -1,14 +1,19 @@ + +include(ECMAddTests) + include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} - ${KDE4_INCLUDES} - ${KDEVPLATFORM_INCLUDE_DIR} ) -kde4_add_unit_test(javaduchaintest javaduchaintest.cpp) +add_executable(javaduchaintest javaduchaintest.cpp) +add_test(javaduchaintest javaduchaintest) +ecm_mark_as_test(javaduchaintest) + target_link_libraries(javaduchaintest kdevjavaduchain - ${QT_QTTEST_LIBRARY} - ${KDEVPLATFORM_TESTS_LIBRARIES} -) \ No newline at end of file + KDevPlatformLanguage + KDevPlatformTests + Qt5::Test +) diff --git a/duchain/tests/javaduchaintest.cpp b/duchain/tests/javaduchaintest.cpp index da6f6d8..e0f5ad4 100644 --- a/duchain/tests/javaduchaintest.cpp +++ b/duchain/tests/javaduchaintest.cpp @@ -1,204 +1,202 @@ /* * This file is part of KDevelop * Copyright 2014 Sven Brauch * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "javaduchaintest.h" #include #include #include #include #include #include #include #include -#include -#include +#include +#include QTEST_MAIN(JavaDUChainTest); using namespace KDevelop; using qsl = QStringList; void JavaDUChainTest::initShell() { AutoTestShell::init(); TestCore* core = new TestCore(); core->initialize(KDevelop::Core::NoUi); DUChain::self()->disablePersistentStorage(); KDevelop::CodeRepresentation::setDiskChangesForbidden(true); } JavaDUChainTest::~JavaDUChainTest() { qDeleteAll(createdFiles); } ReferencedTopDUContext JavaDUChainTest::parse(const QString& code) { TestFile* testfile = new TestFile(code + "\n", "java", 0, QDir::tempPath().append("/")); createdFiles << testfile; testfile->parse((TopDUContext::Features) (TopDUContext::ForceUpdate | TopDUContext::AllDeclarationsContextsUsesAndAST) ); testfile->waitForParsed(5000); if ( testfile->isReady() ) { return testfile->topContext(); } Q_ASSERT_X(false, Q_FUNC_INFO, "Timed out waiting for parser results, aborting all tests"); return NULL; } QString codeInMain(const QString& code) { return QString("public class Foo {\n" " public static void main(String[] args) {\n" " %1\n" " }\n" "}\n").arg(code); } QString codeInMainWithDeclaration(const QString& code) { return codeInMain(" int x;\n %1\n").arg(code); } void JavaDUChainTest::testLocalDeclarations() { QFETCH(QString, code); QFETCH(QStringList, expectedDeclarations); ReferencedTopDUContext top = parse(codeInMain(code)); DUChainReadLocker lock; QVERIFY(top); auto context = top->childContexts().first(); auto classdecls = context->localDeclarations(); QCOMPARE(classdecls.size(), 1); auto classdecl = classdecls.first(); QVERIFY(classdecl->internalContext()); QCOMPARE(classdecl->internalContext()->type(), KDevelop::DUContext::Class); auto funcs = classdecl->internalContext()->localDeclarations(); QCOMPARE(funcs.size(), 1); auto func = funcs.first(); QVERIFY(func->internalContext()); QCOMPARE(func->internalContext()->type(), KDevelop::DUContext::Other); auto variables = func->internalContext()->localDeclarations(); qDebug() << variables; QCOMPARE(variables.size(), expectedDeclarations.size()); for ( auto expected: expectedDeclarations ) { bool found = false; for ( auto existing: variables ) { if ( existing->identifier().toString() == expected ) { found = true; break; } } QVERIFY(found); } } void JavaDUChainTest::testLocalDeclarations_data() { QTest::addColumn("code"); QTest::addColumn("expectedDeclarations"); QTest::newRow("int") << "int x = 3;" << qsl{"x"}; QTest::newRow("int_new") << "int[] numbers = new int[] {1, 2, 3};" << qsl{"numbers"}; } void JavaDUChainTest::testUses() { QFETCH(QString, code); QFETCH(QStringList, expectedUses); ReferencedTopDUContext top = parse(code); DUChainReadLocker lock; QVERIFY(top); auto context = top->childContexts().first(); auto classdecls = context->localDeclarations(); QVERIFY(!classdecls.empty()); auto classdecl = classdecls.first(); QVERIFY(classdecl->internalContext()); QCOMPARE(classdecl->internalContext()->type(), KDevelop::DUContext::Class); auto funcs = classdecl->internalContext()->localDeclarations(); QVERIFY(!funcs.empty()); auto func = funcs.first(); auto funcContext = func->internalContext(); QVERIFY(funcContext); QCOMPARE(funcContext->type(), KDevelop::DUContext::Other); int allUsesCount = funcContext->usesCount(); for ( DUContext* context: funcContext->childContexts() ) allUsesCount += context->usesCount(); QCOMPARE(allUsesCount, expectedUses.size()); for ( auto expected: expectedUses ) { bool found = false; auto uses = funcContext->uses(); int usesCount = funcContext->usesCount(); for ( int i = 0; i < usesCount; i++ ) { if ( uses[i].usedDeclaration(top)->identifier().toString() == expected ) { found = true; break; } } for ( DUContext* context: funcContext->childContexts() ) { if ( found ) break; auto uses = context->uses(); int usesCount = context->usesCount(); for ( int i = 0; i < usesCount; i++ ) { if ( uses[i].usedDeclaration(top)->identifier().toString() == expected ) { found = true; break; } } } QVERIFY(found); } } void JavaDUChainTest::testUses_data() { QTest::addColumn("code"); QTest::addColumn("expectedUses"); QTest::newRow("lvalue") << codeInMainWithDeclaration("x = 5;") << QStringList{"x"}; QTest::newRow("for") << codeInMainWithDeclaration("for ( x = 0; x < 20; x++ ) ;") << QStringList{"x", "x", "x"}; QTest::newRow("rvalue") << codeInMainWithDeclaration("int y = x;") << QStringList{"x"}; QTest::newRow("increment") << codeInMainWithDeclaration("x++;") << QStringList{"x"}; QTest::newRow("function_call") << "public class Foo {\npublic static void main() {\nfunc();\n}\nvoid func() {\n}\n}" << QStringList{"func"}; } -#include "javaduchaintest.moc" - // kate: space-indent on; indent-width 4 diff --git a/duchain/topducontext.cpp b/duchain/topducontext.cpp index 54f1d08..1662a70 100644 --- a/duchain/topducontext.cpp +++ b/duchain/topducontext.cpp @@ -1,249 +1,259 @@ /* 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. */ #include "topducontext.h" #include #include #include #include #include #include - #include #include "helpers.h" //#define DEBUG_SEARCH2 using namespace KDevelop; namespace java { TopDUContext::TopDUContext(const KDevelop::IndexedString& url, const KDevelop::RangeInRevision& range, KDevelop::ParsingEnvironmentFile* file) : KDevelop::TopDUContext(url, range, file) { } TopDUContext::TopDUContext(TopDUContextData& data) : KDevelop::TopDUContext(data) { } REGISTER_DUCHAIN_ITEM(TopDUContext); struct TopDUContext::FindDeclarationsAcceptor { FindDeclarationsAcceptor(DeclarationList& _target, const DeclarationChecker& _check) : target(_target), check(_check) { } void operator() (Declaration* declaration) { #ifdef DEBUG_SEARCH - kDebug() << "accepting" << element->qualifiedIdentifier().toString(); + qDebug() << "accepting" << element->qualifiedIdentifier().toString(); #endif if (check(declaration)) { target.append(declaration); } } DeclarationList& target; const DeclarationChecker& check; }; bool TopDUContext::findDeclarationsInternal(const SearchItem::PtrList& identifiers, const CursorInRevision& position, const AbstractType::Ptr& dataType, DeclarationList& ret, const KDevelop::TopDUContext* source, SearchFlags flags, uint depth) const { Q_UNUSED(source); Q_UNUSED(depth); ENSURE_CAN_READ Q_ASSERT(identifiers.count() >= 1); SearchItem::Ptr identifier = identifiers[0]; DeclarationChecker check(this, position, dataType, flags); FindDeclarationsAcceptor accept(ret, check); #ifdef DEBUG_SEARCH2 - FOREACH_ARRAY(SearchItem::Ptr idTree, identifiers) + for (const SearchItem::Ptr &idTree : identifiers) + { foreach(const QualifiedIdentifier &id, idTree->toList()) - kDebug() << "findDeclarationsInternal" << id.toString(); + qDebug() << "findDeclarationsInternal" << id.toString(); + } bool nextEmpty = identifier->hasNext() ? identifier->next.isEmpty() : true; - kDebug() << "Do direct search? hasNext" << identifier->hasNext() << " isEmpty " << nextEmpty; + qDebug() << "Do direct search? hasNext" << identifier->hasNext() << " isEmpty " << nextEmpty; #endif - + if (identifier->hasNext() && !identifier->next.isEmpty()) { // This is a qualified identifier, do a direct lookup only SearchItem::PtrList directLookup; directLookup.append(identifier); findJavaDeclarationsInternal(directLookup, accept, false); #ifdef DEBUG_SEARCH2 - kDebug() << "Found directly " << ret.count(); + qDebug() << "Found directly " << ret.count(); #endif return true; } - + SearchItem::PtrList singleTypeImports; SearchItem::PtrList typeImportsOnDemand; SearchItem::PtrList singleStaticImports; SearchItem::PtrList staticImportsOnDemand; // Determine which identifiers to search for // Non-static imports foreach (Declaration* import, findLocalDeclarations(globalImportIdentifier())) if (NamespaceAliasDeclaration* alias = dynamic_cast(import)) { if (alias->importIdentifier().last() == Identifier("*")) { typeImportsOnDemand.append( SearchItem::Ptr( new SearchItem( alias->importIdentifier().left(-1), identifier ) ) ) ; } else { if (alias->importIdentifier().last() == identifier->identifier) { singleTypeImports.append( SearchItem::Ptr( new SearchItem( alias->importIdentifier() ) ) ) ; } } } // Static imports foreach (Declaration* import, findLocalDeclarations(Identifier(globalStaticImportIdentifier))) { if (NamespaceAliasDeclaration* alias = dynamic_cast(import)) { if (alias->importIdentifier().last() == Identifier("*")) { staticImportsOnDemand.append( SearchItem::Ptr( new SearchItem( alias->importIdentifier().left(-1), identifier ) ) ) ; } else { if (alias->importIdentifier().last() == identifier->identifier) { singleStaticImports.append( SearchItem::Ptr( new SearchItem( alias->importIdentifier() ) ) ) ; } } } } #ifdef DEBUG_SEARCH - FOREACH_ARRAY(SearchItem::Ptr idTree, singleTypeImports) + for (const SearchItem::Ptr &idTree : singleTypeImports) + { foreach(const QualifiedIdentifier &id, idTree->toList()) - kDebug() << "Single type imported: " << id.toString(); + qDebug() << "Single type imported: " << id.toString(); + } - FOREACH_ARRAY(SearchItem::Ptr idTree, typeImportsOnDemand) + for (const SearchItem::Ptr &idTree : typeImportsOnDemand) + { foreach(const QualifiedIdentifier &id, idTree->toList()) - kDebug() << "Type import on demand: " << id.toString(); + qDebug() << "Type import on demand: " << id.toString(); + } - FOREACH_ARRAY(SearchItem::Ptr idTree, singleStaticImports) + for (const SearchItem::Ptr &idTree : singleStaticImports) + { foreach(const QualifiedIdentifier &id, idTree->toList()) - kDebug() << "Single static imported: " << id.toString(); + qDebug() << "Single static imported: " << id.toString(); + } - FOREACH_ARRAY(SearchItem::Ptr idTree, staticImportsOnDemand) + for (const SearchItem::Ptr &idTree : staticImportsOnDemand) + { foreach(const QualifiedIdentifier &id, idTree->toList()) - kDebug() << "Statics imported on demand: " << id.toString(); + qDebug() << "Statics imported on demand: " << id.toString(); + } #endif ///The actual scopes are found within applyAliases, and each complete qualified identifier is given to FindDeclarationsAcceptor. ///That stores the found declaration to the output. findJavaDeclarationsInternal(singleTypeImports, accept, false); if (foundEnough(ret, flags)) { #ifdef DEBUG_SEARCH2 - kDebug() << "Found from single type" << ret.count(); + qDebug() << "Found from single type" << ret.count(); #endif return true; } findJavaDeclarationsInternal(singleStaticImports, accept, true); if (foundEnough(ret, flags)) { #ifdef DEBUG_SEARCH2 - kDebug() << "Found from single static" << ret.count(); + qDebug() << "Found from single static" << ret.count(); #endif return true; } findJavaDeclarationsInternal(typeImportsOnDemand, accept, false); if (foundEnough(ret, flags)) { #ifdef DEBUG_SEARCH2 - kDebug() << "Found from type on demand" << ret.count(); + qDebug() << "Found from type on demand" << ret.count(); #endif return true; } findJavaDeclarationsInternal(staticImportsOnDemand, accept, true); if (foundEnough(ret, flags)) { #ifdef DEBUG_SEARCH2 - kDebug() << "Found from static on demand" << ret.count(); + qDebug() << "Found from static on demand" << ret.count(); #endif return true; } #ifdef DEBUG_SEARCH2 - kDebug() << "None found" << ret.count(); + qDebug() << "None found" << ret.count(); #endif return true; } template void TopDUContext::findJavaDeclarationsInternal( const SearchItem::PtrList& identifiers, Acceptor& accept, bool staticOnly ) const { - FOREACH_ARRAY(SearchItem::Ptr identifier, identifiers) { + for (SearchItem::Ptr identifier : identifiers) + { QualifiedIdentifier id(identifier->identifier); while (identifier->hasNext()) { identifier = *identifier->next.data(); id.push(identifier->identifier); } #ifdef DEBUG_SEARCH2 - kDebug() << "checking" << id.toString(); + qDebug() << "checking" << id.toString(); #endif if(!id.isEmpty()) { - PersistentSymbolTable::FilteredDeclarationIterator filter = PersistentSymbolTable::self().getFilteredDeclarations(id, recursiveImportIndices()); + PersistentSymbolTable::FilteredDeclarationIterator filter = PersistentSymbolTable::self().filteredDeclarations(id, recursiveImportIndices()); if (filter) { for(; filter; ++filter) { const IndexedDeclaration iDecl = *filter; Declaration* aliasDecl = iDecl.data(); #ifdef DEBUG_SEARCH2 - kDebug() << "Found declaration" << aliasDecl; + qDebug() << "Found declaration" << aliasDecl; #endif if(!aliasDecl) continue; if(aliasDecl->identifier() != id.last()) { //Since we have retrieved the aliases by hash only, we still need to compare the name #ifdef DEBUG_SEARCH2 - kDebug() << "Dumped as not the same identifier" << aliasDecl->identifier().toString() << id.last().toString(); + qDebug() << "Dumped as not the same identifier" << aliasDecl->identifier().toString() << id.last().toString(); #endif continue; } ClassMemberDeclaration* classMemberDecl = dynamic_cast(aliasDecl); // TODO check logic here if (staticOnly && (!classMemberDecl || !classMemberDecl->isStatic())) { #ifdef DEBUG_SEARCH2 - kDebug() << "Dumped as not static where search requested static only" << aliasDecl->identifier().toString(); + qDebug() << "Dumped as not static where search requested static only" << aliasDecl->identifier().toString(); #endif continue; } #ifdef DEBUG_SEARCH2 - kDebug() << "Trying to accept" << aliasDecl->identifier().toString(); + qDebug() << "Trying to accept" << aliasDecl->identifier().toString(); #endif accept(aliasDecl); } } } #ifdef DEBUG_SEARCH2 - kDebug() << "Finished" << id.toString(); + qDebug() << "Finished" << id.toString(); #endif } } } diff --git a/duchain/typebuilder.cpp b/duchain/typebuilder.cpp index 3115f8f..c2645e9 100644 --- a/duchain/typebuilder.cpp +++ b/duchain/typebuilder.cpp @@ -1,298 +1,298 @@ /* This file is part of KDevelop Copyright 2006-2008 Hamish Rodda 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. */ #include "typebuilder.h" #include "editorintegrator.h" #include "parsesession.h" #include "declarationbuilder.h" //#define DEBUG #ifdef DEBUG #define ifDebug(x) x; #else #define ifDebug(x) #endif using namespace KDevelop; namespace java { TypeBuilder::TypeBuilder() : m_buildCompleteTypes(true) { } bool TypeBuilder::buildCompleteTypes() const { return m_buildCompleteTypes; } void TypeBuilder::setBuildCompleteTypes(bool completeTypes) { m_buildCompleteTypes = completeTypes; } StructureType* TypeBuilder::openClass(bool interface, bool parameters) { Q_UNUSED( interface ); Q_UNUSED( parameters ); StructureType* classType = /*parameters ? new ParameterizedType() : */new StructureType(); //classType->setClassType(interface ? StructureType::Interface : StructureType::Class); return classType; } void TypeBuilder::visitMethodDeclaration(MethodDeclarationAst * node) { clearLastType(); visitNode(node->returnType); FunctionType::Ptr functionType = FunctionType::Ptr(new FunctionType()); functionType->setModifiers(parseModifiers(node->modifiers)); if (lastType()) functionType->setReturnType(lastType()); openType(functionType); TypeBuilderBase::visitMethodDeclaration(node); closeType(); } void TypeBuilder::visitParameterDeclarationEllipsis(ParameterDeclarationEllipsisAst* node) { TypeBuilderBase::visitParameterDeclarationEllipsis(node); if (hasCurrentType()) if (FunctionType::Ptr function = currentType()) function->addArgument(lastType()); } void TypeBuilder::visitInterfaceMethodDeclaration(InterfaceMethodDeclarationAst * node) { clearLastType(); visitNode(node->returnType); FunctionType::Ptr functionType = FunctionType::Ptr(new FunctionType()); functionType->setModifiers(parseModifiers(node->modifiers)); if (lastType()) functionType->setReturnType(lastType()); openType(functionType); TypeBuilderBase::visitInterfaceMethodDeclaration(node); closeType(); } void TypeBuilder::visitConstructorDeclaration(ConstructorDeclarationAst * node) { FunctionType::Ptr functionType = FunctionType::Ptr(new FunctionType()); functionType->setModifiers(parseModifiers(node->modifiers)); openType(functionType); TypeBuilderBase::visitConstructorDeclaration(node); closeType(); } void TypeBuilder::visitClassDeclaration(ClassDeclarationAst *node) { StructureType::Ptr classType = StructureType::Ptr(openClass(false, node->typeParameters)); openType(classType); classTypeOpened( currentAbstractType() ); //This callback is needed, because the type of the class-declaration needs to be set early so the class can be referenced from within itself TypeBuilderBase::visitClassDeclaration(node); closeType(); } void TypeBuilder::visitInterfaceDeclaration(InterfaceDeclarationAst * node) { StructureType::Ptr classType = StructureType::Ptr(openClass(true, node->typeParameters)); openType(classType); classTypeOpened( currentAbstractType() ); //This callback is needed, because the type of the class-declaration needs to be set early so the class can be referenced from within itself TypeBuilderBase::visitInterfaceDeclaration(node); closeType(); } void TypeBuilder::visitBuiltInType(BuiltInTypeAst * node) { bool openedType = false; if (node) { uint type = IntegralType::TypeNone; switch (node->type) { case BuiltInTypeVoid: type = IntegralType::TypeVoid; break; case BuiltInTypeBoolean: type = IntegralType::TypeBoolean; break; case BuiltInTypeByte: type = IntegralType::TypeByte; break; case BuiltInTypeChar: type = IntegralType::TypeChar; break; case BuiltInTypeShort: type = IntegralType::TypeShort; break; case BuiltInTypeInt: type = IntegralType::TypeInt; break; case BuiltInTypeFloat: type = IntegralType::TypeFloat; break; case BuiltInTypeLong: type = IntegralType::TypeLong; break; case BuiltInTypeDouble: type = IntegralType::TypeDouble; break; } // TODO move this out and pass the modifiers as well /* // Equal value TypeModifiers mod = static_cast(node->modifiers); if (JavaType* type = dynamic_cast(currentAbstractType().data())) type->setModifiers(mod);*/ IntegralType::Ptr integral(new IntegralType(type)); //integral->setModifiers(modifiers); openedType = true; openType(integral); } TypeBuilderBase::visitBuiltInType(node); if (openedType) closeType(); } bool TypeBuilder::nodeValid(AstNode* node) const { return node && node->startToken <= node->endToken; } void TypeBuilder::visitOptionalArrayBuiltInType(OptionalArrayBuiltInTypeAst * node) { visitNode(node->type); if (nodeValid(node->declaratorBrackets)) { ArrayType::Ptr array(new ArrayType()); array->setElementType(lastType()); if( node->declaratorBrackets ) { array->setDimension(node->declaratorBrackets->bracketCount); } else { array->setDimension(0); } injectType(array); } } void TypeBuilder::visitTypeArgument(TypeArgumentAst * node) { //node-> TypeBuilderBase::visitTypeArgument(node); } uint TypeBuilder::parseModifiers(OptionalModifiersAst * node) const { uint mod = AbstractType::NoModifiers; // TODO handle the following ... ModifierPrivate, ModifierPublic, ModifierProtected if (node->modifiers & ModifierTransient) mod |= AbstractType::TransientModifier; if (node->modifiers & ModifierVolatile) mod |= AbstractType::VolatileModifier; return mod; } void TypeBuilder::visitClassOrInterfaceTypeName(ClassOrInterfaceTypeNameAst * node) { m_currentIdentifier.clear(); TypeBuilderBase::visitClassOrInterfaceTypeName(node); if (buildCompleteTypes() && openTypeFromName(m_currentIdentifier, node, true)) { { //DUChainReadLocker lock(DUChain::lock()); - //kDebug() << "Searching for type " << m_currentIdentifier.toStringList().join(".") << ", found " << currentAbstractType()->toString(); + //qDebug() << "Searching for type " << m_currentIdentifier.toStringList().join(".") << ", found " << currentAbstractType()->toString(); } closeType(); } else { unresolvedIdentifier(DUContextPointer(currentContext()), m_currentIdentifier); } } void TypeBuilder::visitClassOrInterfaceTypeNamePart(ClassOrInterfaceTypeNamePartAst * node) { m_currentIdentifier.push(identifierForNode(node->identifier)); TypeBuilderBase::visitClassOrInterfaceTypeNamePart(node); } void TypeBuilder::visitEnumDeclaration(EnumDeclarationAst* node) { StructureType::Ptr classType = StructureType::Ptr(openClass(false, false)); openType(classType); classTypeOpened( currentAbstractType() ); //This callback is needed, because the type of the class-declaration needs to be set early so the class can be referenced from within itself TypeBuilderBase::visitEnumDeclaration(node); closeType(); } void TypeBuilder::visitEnumConstant(EnumConstantAst* node) { openType(EnumerationType::Ptr(new EnumerationType())); TypeBuilderBase::visitEnumConstant(node); closeType(); } } diff --git a/duchain/typebuilder.h b/duchain/typebuilder.h index 2610666..93516bb 100644 --- a/duchain/typebuilder.h +++ b/duchain/typebuilder.h @@ -1,82 +1,82 @@ /* This file is part of KDevelop Copyright 2006-2008 Hamish Rodda 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. */ #ifndef TYPEBUILDER_H #define TYPEBUILDER_H #include "contextbuilder.h" #include #include #include -#include "javaduchainexport.h" +#include "javaduchain_export.h" namespace java { typedef KDevelop::AbstractTypeBuilder TypeBuilderBase; /** * Create types from an AstNode tree. * * \note This builder overrides visitDeclarator, in order to support * array types; parent classes will not have * their visitDeclarator function called. */ class KDEVJAVADUCHAIN_EXPORT TypeBuilder: public TypeBuilderBase { public: TypeBuilder(); bool buildCompleteTypes() const; void setBuildCompleteTypes(bool completeTypes); protected: virtual void visitClassDeclaration(ClassDeclarationAst *node); virtual void visitClassOrInterfaceTypeName(ClassOrInterfaceTypeNameAst *node); virtual void visitClassOrInterfaceTypeNamePart(ClassOrInterfaceTypeNamePartAst *node); virtual void visitTypeArgument(TypeArgumentAst *node); virtual void visitOptionalArrayBuiltInType(OptionalArrayBuiltInTypeAst * node); virtual void visitEnumDeclaration(EnumDeclarationAst* node); virtual void visitEnumConstant(EnumConstantAst* node); virtual void visitMethodDeclaration(MethodDeclarationAst *node); virtual void visitParameterDeclarationEllipsis(ParameterDeclarationEllipsisAst* node); virtual void visitInterfaceMethodDeclaration(InterfaceMethodDeclarationAst * node); virtual void visitConstructorDeclaration(ConstructorDeclarationAst *node); virtual void visitInterfaceDeclaration(InterfaceDeclarationAst *node); virtual void visitBuiltInType(BuiltInTypeAst *node); private: bool nodeValid(AstNode* node) const; KDevelop::StructureType* openClass(bool interface, bool parameters); KDevelop::FunctionType* openFunction(); uint parseModifiers(OptionalModifiersAst* node) const; QList m_rememberClassNames; KDevelop::QualifiedIdentifier m_currentIdentifier; bool m_buildCompleteTypes; }; } #endif // TYPEBUILDER_H diff --git a/duchain/typeconversion.cpp b/duchain/typeconversion.cpp index ebaaf79..fadef69 100644 --- a/duchain/typeconversion.cpp +++ b/duchain/typeconversion.cpp @@ -1,602 +1,602 @@ /* Copyright 2007 David Nolden Copyright 2009 Hamish Rodda 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. */ #include "typeconversion.h" #include "overloadresolver.h" #include #include #include #include #include #include #include #include #include #include "typeutils.h" using namespace KDevelop; using namespace TypeUtils; namespace java { struct ImplicitConversionParams { IndexedType from, to; bool fromLValue, noUserDefinedConversion; - + bool operator==(const ImplicitConversionParams& rhs) const { return from == rhs.from && to == rhs.to && fromLValue == rhs.fromLValue && noUserDefinedConversion == rhs.noUserDefinedConversion; } }; uint qHash(const ImplicitConversionParams& params) { return (params.from.hash() * 36109 + params.to.hash()) * (params.fromLValue ? 111 : 53) * (params.noUserDefinedConversion ? 317293 : 1); } class TypeConversionCache { public: QHash m_implicitConversionResults; /* QHash, uint> m_standardConversionResults; QHash, uint> m_userDefinedConversionResults;*/ // QHash, bool> m_isPublicBaseCache; }; QHash typeConversionCaches; QMutex typeConversionCacheMutex; void TypeConversion::startCache() { QMutexLocker lock(&typeConversionCacheMutex); if(!typeConversionCaches.contains(QThread::currentThreadId())) typeConversionCaches[QThread::currentThreadId()] = new TypeConversionCache; } void TypeConversion::stopCache() { QMutexLocker lock(&typeConversionCacheMutex); if(typeConversionCaches.contains(QThread::currentThreadId())) { delete typeConversionCaches[QThread::currentThreadId()]; typeConversionCaches.remove(QThread::currentThreadId()); } } TypeConversion::TypeConversion(const TopDUContext* topContext) : m_topContext(topContext) { QMutexLocker lock(&typeConversionCacheMutex); QHash::iterator it = typeConversionCaches.find(QThread::currentThreadId()); if(it != typeConversionCaches.end()) m_cache = *it; else m_cache = 0; } TypeConversion::~TypeConversion() { } /** * All information taken from iso c++ draft * * Standard-conversion-sequence: * - zero or one conversion from the following set: lvalue-to-rvalue conversion, array-to-pointer conversion, function-to-pointer conversion * - zero or one conversion from the following set: integral promotions, floating point promotions, integral conversions, floating point conversions, floating-integral conversions, pointer conversions, pointer to member conversions, and boolean conversions. * * Standard-conversion-sequence will be applied to expression when it needs to be converted to another type. * * Note: lvalue = reference to existing object * rvalue = copied object * * When is an expression implicitly converted? : * - When used as operands of operators. * - When used in a condition statement(destination type is bool) * - When used in the expression of a switch statement * - When used as the source expression for an initialization(includes argument in function-call and return-statement) * * User-defined conversions: * - Constructors and conversion-functions. * - At most one such conversion is applied when doing implicit type-conversion * */ /** * An implicit conversion-sequence is one of the following: * - a standard conversion sequence * - a user-defined conversion sequence * - an ellipsis conversion sequence * * */ uint TypeConversion::implicitConversion( IndexedType _from, IndexedType _to, bool fromLValue, bool noUserDefinedConversion ) { m_baseConversionLevels = 0; int conv = 0; - + ImplicitConversionParams params; params.from = _from; params.to = _to; params.fromLValue = fromLValue; params.noUserDefinedConversion = noUserDefinedConversion; - + if(m_cache) { QHash::const_iterator it = m_cache->m_implicitConversionResults.constFind(params); if(it != m_cache->m_implicitConversionResults.constEnd()) return *it; } - + AbstractType::Ptr to = unAliasedType(_to.abstractType()); AbstractType::Ptr from = unAliasedType(_from.abstractType()); - + if( !from || !to ) { problem( from, to, "one type is invalid" ); goto ready; }else{ - - //kDebug(9007) << "Checking conversion from " << from->toString() << " to " << to->toString(); + + //qDebug(9007) << "Checking conversion from " << from->toString() << " to " << to->toString(); ReferenceType::Ptr fromReference = from.cast(); if( fromReference ) fromLValue = true; ///iso c++ draft 13.3.3.1.4 reference-binding, modeled roughly ReferenceType::Ptr toReference = to.cast(); if( toReference ) { AbstractType::Ptr realFrom = realType(from, m_topContext); AbstractType::Ptr realTo = realType(to, m_topContext); if(!realFrom || !realTo) { problem( from, to, "one type is invalid" ); goto ready; } if( fromLValue && ((realTo->modifiers() & AbstractType::ConstModifier) || (realTo->modifiers() & AbstractType::ConstModifier) == isConstant(from)) ) { ///Since from is an lvalue, and the constant-specification matches, we can maybe directly create a reference //Either identity-conversion: if( identityConversion( realFrom, realTo ) ) { conv = ExactMatch + 2*ConversionRankOffset; goto ready; } //Or realType(toReference) is a public base-class of realType(fromReference) StructureType::Ptr fromClass = realFrom.cast(); StructureType::Ptr toClass = realTo.cast(); if( fromClass && toClass && isPublicBaseClass( fromClass, toClass, m_topContext, &m_baseConversionLevels ) ) { conv = ExactMatch + 2*ConversionRankOffset; goto ready; } } //We cannot directly create a reference, but maybe there is a user-defined conversion that creates a compatible reference, as in iso c++ 13.3.3.1.4.1 if( !noUserDefinedConversion ) { if( int rank = userDefinedConversion( from, to, fromLValue, true ) ) { conv = rank + ConversionRankOffset; goto ready; } } if( realTo->modifiers() & AbstractType::ConstModifier ) { //For constant references, the compiler can create a temporary object holding the converted value. So just forget whether the types are references. conv = implicitConversion( realType(from, m_topContext)->indexed(), realType(to, m_topContext)->indexed(), fromLValue, noUserDefinedConversion ); goto ready; } } { int tempConv = 0; //This is very simplified, see iso c++ draft 13.3.3.1 if( (tempConv = standardConversion(from,to)) ) { tempConv += 2*ConversionRankOffset; if( tempConv > conv ) conv = tempConv; } if( !noUserDefinedConversion ) { if( (tempConv = userDefinedConversion(from, to, fromLValue)) ) { tempConv += ConversionRankOffset; if( tempConv > conv ) conv = tempConv; } } - + if( (tempConv = ellipsisConversion(from, to)) && tempConv > conv ) conv = tempConv; } } ready: - + if(m_cache) m_cache->m_implicitConversionResults.insert(params, conv); - + return conv; } int TypeConversion::baseConversionLevels() const { return m_baseConversionLevels; } ///Helper for standardConversion(..) that makes sure that when one category is taken out of the possible ones, the earlier are taken out too, because categories must be checked in order. int removeCategories( int categories, ConversionCategories remove ) { for( int a = 1; a <= remove; a*=2 ) { categories &= ~a; } return categories; } ///if myRank is better than rank, rank will be set to myRank void maximizeRank( ConversionRank& rank, ConversionRank myRank ) { if( myRank > rank ) rank = myRank; } ///Returns the worse of the both given ranks ConversionRank worseRank( ConversionRank rank1, ConversionRank rank2 ) { return rank1 > rank2 ? rank2 : rank1; } - + ConversionRank TypeConversion::pointerConversion( PointerType::Ptr from, PointerType::Ptr to ) { - + //We can convert non-const -> const, but not const -> non-const // if(to->modifiers() & AbstractType::ConstModifier || !(from->modifiers()& AbstractType::ConstModifier)) { if(!from || !to) return NoMatch; - + AbstractType::Ptr nextFrom = unAliasedType(from->baseType()); AbstractType::Ptr nextTo = unAliasedType(to->baseType()); if(!nextTo || !nextFrom) return NoMatch; if((nextFrom->modifiers() & AbstractType::ConstModifier) && !(nextTo->modifiers() & AbstractType::ConstModifier)) return NoMatch; //Cannot convert const -> non-const - + PointerType::Ptr pointerFrom = nextFrom.cast(); PointerType::Ptr pointerTo = nextTo.cast(); if(pointerFrom && pointerTo) return pointerConversion(pointerFrom, pointerTo); - + StructureType::Ptr fromClass = nextFrom.cast(); StructureType::Ptr toClass = nextTo.cast(); if( toClass && fromClass ) if(toClass->modifiers() & AbstractType::ConstModifier || !(fromClass->modifiers()& AbstractType::ConstModifier)) if( isPublicBaseClass( fromClass, toClass, m_topContext, &m_baseConversionLevels ) ) return ((toClass->modifiers() & AbstractType::ConstModifier) != (fromClass->modifiers() & AbstractType::ConstModifier)) ? Conversion : ExactMatch; - + bool changed = false; //Change the constness matches, so they are equal if compatible if(nextTo->modifiers() & AbstractType::ConstModifier) { nextFrom->setModifiers(nextFrom->modifiers() | AbstractType::ConstModifier); changed = true; } - + if(identityConversion(nextFrom, nextTo)) return changed ? Conversion : ExactMatch; - + // } - + return NoMatch; } /** * * **/ ConversionRank TypeConversion::standardConversion( AbstractType::Ptr from, AbstractType::Ptr to, int categories, int maxCategories ) { /** Lowest conversion-rank of all sub-conversions is returned * See iso c++ draft 13.3.3.1.1 * * Conversions from up to 3 different categories are allowed * * Table about category and rank: * * Conversion Category Rank iso c++ clause * ----------------------------------------------------------------------------------------------------- * No conversion Identity Exact Match * Lvalue-to-rvalue conv. Lvalue Transformation Exact Match 4.1 * Array-to-pointer conv. Lvalue Transformation Exact Match 4.2 * Function-to-pointer conv. Lvalue Transformation Exact Match 4.3 * Qualification conversion Qualification Adjustment Exact Match 4.4 * Integral promotions Promotion Promotion 4.5 * Floating point promotion Promotion Promotion 4.6 * Integral conversions Conversion Conversion 4.7 * Floating point conversions Conversion Conversion 4.8 * Floating-integral conversions Conversion Conversion 4.9 * Pointer conversions Conversion Conversion 4.10 * Pointer to member conversions Conversion Conversion 4.11 * Boolean conversions Conversion Conversion 4.12 * * A standard-conversion may consist of up to 3 conversions from different categories * * * This function achieves the rules recursively. Performance-wise that may not be perfect, because sometimes many different paths can are followed. **/ from = unAliasedType(from); to = unAliasedType(to); if( (categories & IdentityCategory) && identityConversion( from, to ) ) return ExactMatch; if(!from || !to) return NoMatch; - + ConversionRank bestRank = NoMatch; ///Try lvalue-transformation category if( (categories & LValueTransformationCategory) ) { bool constRef = false; if( isReferenceType(from) ) { ///Transform lvalue to rvalue. Iso c++ draft 4.1 modeled roughly - + AbstractType::Ptr fromNonConstant = realType(from, m_topContext)->indexed().abstractType(); //When copying, the type becomes non-constant if(fromNonConstant && fromNonConstant->modifiers() & AbstractType::ConstModifier) fromNonConstant->setModifiers(fromNonConstant->modifiers() & ~(AbstractType::ConstModifier)); - + ConversionRank ret = standardConversion( fromNonConstant, to, removeCategories(categories,LValueTransformationCategory), maxCategories-1 ); maximizeRank( bestRank, ret ); }else if( ArrayType::Ptr array = realType(from, m_topContext, &constRef).cast() ) { //realType(from) is used here so reference-to-array can be transformed to a pointer. This does not exactly follow the standard I think, check that. ///Transform array to pointer. Iso c++ draft 4.2 modeled roughly. PointerType::Ptr p( new PointerType() ); if (constRef) p->setModifiers(AbstractType::ConstModifier); p->setBaseType(array->elementType()); ConversionRank rank = standardConversion( p.cast(), to, removeCategories(categories,LValueTransformationCategory), maxCategories-1 ); maximizeRank( bestRank, worseRank(rank, ExactMatch ) ); } else if( FunctionType::Ptr function = realType(from, m_topContext, &constRef).cast() ) { ///Transform lvalue-function. Iso c++ draft 4.3 //This code is nearly the same as the above array-to-pointer conversion. Maybe it should be merged. PointerType::Ptr p( new PointerType() ); if (constRef) p->setModifiers(AbstractType::ConstModifier); p->setBaseType( function.cast() ); ConversionRank rank = standardConversion( p.cast(), to, removeCategories(categories,LValueTransformationCategory), maxCategories-1 ); maximizeRank( bestRank, worseRank(rank, ExactMatch ) ); }else if(from->modifiers() & AbstractType::ConstModifier) { ///We can transform a constant lvalue to a non-constant rvalue AbstractType::Ptr fromNonConstant = from->indexed().abstractType(); fromNonConstant->setModifiers(fromNonConstant->modifiers() & ~(AbstractType::ConstModifier)); ConversionRank ret = standardConversion( fromNonConstant, to, removeCategories(categories,LValueTransformationCategory), maxCategories-1 ); maximizeRank( bestRank, ret ); } } // if( categories & QualificationAdjustmentCategory ) { // PointerType::Ptr pnt = from.cast(); -// +// // ///@todo iso c++ 4.4.2 etc: pointer to member // } EnumerationType::Ptr toEnumeration = to.cast(); if(toEnumeration) { //Eventually convert enumerator -> enumeration if the enumeration equals EnumeratorType::Ptr fromEnumerator = from.cast(); if(fromEnumerator) { Declaration* enumeratorDecl = fromEnumerator->declaration(m_topContext); Declaration* enumerationDecl = toEnumeration->declaration(m_topContext); if(enumeratorDecl && enumerationDecl && enumeratorDecl->context()->owner() == enumerationDecl) return ExactMatch; //Converting an enumeration value into its own enumerator type, perfect match. } ///iso c++ 7.2.9: No conversion or promotion to enumerator types is possible return bestRank; } if( categories & PromotionCategory ) { IntegralType::Ptr integral = from.cast(); if( integral ) { ///Integral promotions, iso c++ 4.5 if( integerConversionRank(integral) < unsignedIntConversionRank && integral->dataType() != IntegralType::TypeBoolean && integral->dataType() != IntegralType::TypeWchar_t && integral->dataType() != IntegralType::TypeVoid ) { ///iso c++ 4.5.1 ///@todo re-create a mini repository for fast lookup of such integral types, so we don't have to do allocations here AbstractType::Ptr newFrom( new IntegralType(IntegralType::TypeInt) ); newFrom->setModifiers((integral->modifiers() & AbstractType::UnsignedModifier) ? AbstractType::UnsignedModifier : AbstractType::NoModifiers); ConversionRank rank = standardConversion( newFrom, to, removeCategories(categories,PromotionCategory), maxCategories-1 ); maximizeRank( bestRank, worseRank(rank, Promotion ) ); } ///Floating point promotion, iso c++ 4.6 if( integral->dataType() == IntegralType::TypeDouble ) { AbstractType::Ptr newFrom( new IntegralType(IntegralType::TypeDouble) ); ConversionRank rank = standardConversion( newFrom, to, removeCategories(categories,PromotionCategory), maxCategories-1 ); maximizeRank( bestRank, worseRank(rank, Promotion ) ); } } } if( categories & ConversionCategory ) { IntegralType::Ptr fromIntegral = from.cast(); EnumerationType::Ptr fromEnumeration = fromIntegral.cast(); EnumeratorType::Ptr fromEnumerator = fromIntegral.cast(); IntegralType::Ptr toIntegral = to.cast(); if( fromIntegral && toIntegral ) { ///iso c++ 4.7 integral conversion: we can convert from any integer type to any other integer type, and from enumeration-type to integer-type if( (fromEnumeration || fromEnumerator || isIntegerType(fromIntegral)) && isIntegerType(toIntegral) ) { maximizeRank( bestRank, Conversion ); } ///iso c++ 4.8 floating point conversion: any floating-point to any other floating-point if( isFloatingPointType(fromIntegral) && isFloatingPointType(toIntegral) ) { maximizeRank( bestRank, Conversion ); } ///iso c++ 4.9 floating-integral conversion: floating point can be converted to integral, enumeration and integral can be converted to floating point if( ( ( fromEnumeration || fromEnumerator || isIntegerType(fromIntegral) ) && isFloatingPointType(toIntegral) ) || ( isFloatingPointType(fromIntegral) && isIntegerType(toIntegral) ) ) { maximizeRank( bestRank, Conversion ); } } ///iso c++ 4.10 pointer conversion: null-type con be converted to pointer PointerType::Ptr fromPointer = from.cast(); PointerType::Ptr toPointer = to.cast(); if( isNullType(from) && toPointer ) { maximizeRank( bestRank, Conversion ); } ///Pointer can be converted to void* if( fromPointer && toPointer && isVoidType(toPointer->baseType()) ) { maximizeRank( bestRank, Conversion ); } ///iso c++ 4.10.3 - class-pointer conversion if( fromPointer && toPointer /*&& fromPointer->cv() == toPointer->cv()*/ ) maximizeRank( bestRank, pointerConversion(fromPointer, toPointer) ); ///@todo pointer-to-member conversion ///iso c++ 4.12 Boolean conversions if( toIntegral && toIntegral->dataType() == IntegralType::TypeBoolean ) { //We are converting to a boolean value if( fromPointer || fromEnumeration || fromEnumerator || (fromIntegral && (isIntegerType(fromIntegral) || isFloatingPointType(fromIntegral))) ) { maximizeRank( bestRank, Conversion ); } } } return bestRank; } bool TypeConversion::identityConversion( AbstractType::Ptr from, AbstractType::Ptr to ) { - + from = TypeUtils::unAliasedType(from); to = TypeUtils::unAliasedType(to); - + if( !from && !to ) return true; else if( !from || !to ) return false; //ConstantIntegralType::equals does not return true on equals in this case, but the type is compatible. if(from.cast() && typeid(*to) == typeid(IntegralType)) return true; - return from->equals(to.unsafeData()); + return from->equals(to.data()); } void TypeConversion::problem( AbstractType::Ptr from, AbstractType::Ptr to, const QString& desc ) { Q_UNUSED(from) Q_UNUSED(to) Q_UNUSED(desc) } ConversionRank TypeConversion::userDefinedConversion( AbstractType::Ptr from, AbstractType::Ptr to, bool fromLValue, bool secondConversionIsIdentity ) { /** * Two possible cases: * - from is a class, that has a conversion-function * - to is a class that has a converting(non-explicit) matching constructor **/ ConversionRank bestRank = NoMatch; bool fromConst = false; AbstractType::Ptr realFrom( realType(from, m_topContext, &fromConst) ); StructureType::Ptr fromClass = realFrom.cast(); { ///Try user-defined conversion using a conversion-function, iso c++ 12.3 if( fromClass ) { ///Search for a conversion-function that has a compatible output QHash conversionFunctions; getMemberFunctions(fromClass, m_topContext, conversionFunctions, "operator{...cast...}", fromConst); for( QHash::const_iterator it = conversionFunctions.constBegin(); it != conversionFunctions.constEnd(); ++it ) { if(isAccessible(it.value())) { AbstractType::Ptr convertedType( it.key()->returnType() ); ConversionRank rank = standardConversion( convertedType, to ); if( rank != NoMatch && (!secondConversionIsIdentity || rank == ExactMatch) ) { //We have found a matching conversion-function if( identityConversion(realType(convertedType, m_topContext), to) ) maximizeRank( bestRank, ExactMatch ); else maximizeRank( bestRank, Conversion ); } } } } } AbstractType::Ptr realTo( realType(to, m_topContext) ); { ///Try conversion using constructor StructureType::Ptr toClass = realTo.cast(); //@todo think whether the realType(..) is ok if( toClass && toClass->declaration(m_topContext) ) { if( fromClass ) { if( isPublicBaseClass(fromClass, toClass, m_topContext, &m_baseConversionLevels ) ) { ///@todo check whether this is correct //There is a default-constructor in toClass that initializes from const toClass&, which fromClass can be converted to maximizeRank( bestRank, Conversion ); } } DUContextPointer ptr(toClass->declaration(m_topContext)->logicalInternalContext(m_topContext)); OverloadResolver resolver( ptr, TopDUContextPointer( const_cast(m_topContext) ) ); Declaration* function = resolver.resolveConstructor( OverloadResolver::Parameter( from, fromLValue ), true, true ); if( function && isAccessible(dynamic_cast(function)) ) { //We've successfully located an overloaded constructor that accepts the argument if( to == realFrom ) maximizeRank( bestRank, ExactMatch ); else maximizeRank( bestRank, Conversion ); } } } return bestRank; } bool TypeConversion::isAccessible(const ClassMemberDeclaration* decl) { ///@todo Use Cpp::isAccessible here if(!decl) return false; return decl->accessPolicy() == Declaration::Public; } ConversionRank TypeConversion::ellipsisConversion( AbstractType::Ptr from, AbstractType::Ptr to ) { Q_UNUSED(from) Q_UNUSED(to) return NoMatch; } -} \ No newline at end of file +} diff --git a/duchain/typeutils.cpp b/duchain/typeutils.cpp index 02e75a8..8ea0f98 100644 --- a/duchain/typeutils.cpp +++ b/duchain/typeutils.cpp @@ -1,291 +1,291 @@ /* Copyright 2007 David Nolden 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. */ #include "typeutils.h" #include #include #include #include #include "typeconversion.h" #include "declarationbuilder.h" namespace TypeUtils { using namespace KDevelop; AbstractType::Ptr realType(const AbstractType::Ptr& _base, const TopDUContext* /*topContext*/, bool* constant) { if(constant) *constant = false; AbstractType::Ptr base = _base; ReferenceType::Ptr ref = base.cast(); TypeAliasType::Ptr alias = base.cast(); while( ref || alias ) { uint hadModifiers = base->modifiers(); if(ref) { base = ref->baseType(); }else{ base = alias->type(); } if(base) base->setModifiers(base->modifiers() | hadModifiers); - + ref = base.cast(); alias = base.cast(); } return base; } AbstractType::Ptr realTypeKeepAliases(const AbstractType::Ptr& _base) { AbstractType::Ptr base = _base; ReferenceType::Ptr ref = base.cast(); while( ref ) { uint hadModifiers = base->modifiers(); base = ref->baseType(); if(base) base->setModifiers(base->modifiers() | hadModifiers); - + ref = base.cast(); } return base; } bool isPointerType(const AbstractType::Ptr& type) { return realType(type, 0).cast(); } bool isReferenceType(const AbstractType::Ptr& type) { return type.cast(); } bool isConstant( const AbstractType::Ptr& t ) { return t && t->modifiers() & AbstractType::ConstModifier; } bool isNullType( const AbstractType::Ptr& t ) { ConstantIntegralType::Ptr integral = t.cast(); if( integral && integral->dataType() == IntegralType::TypeInt && integral->value() == 0 ) return true; else return false; } const int unsignedIntConversionRank = 4; int integerConversionRank( const IntegralType::Ptr& type ) { /** * Ranks: * 1 - bool * 2 - 1 byte, char * 3 - 2 byte, short int, wchar_t, unsigned short int * 4 - 4 byte, int, unsigned int * 5 - 4 byte, long int * 6 - 4 byte, long long int **/ switch( type->dataType() ) { case IntegralType::TypeBoolean: return 1; break; case IntegralType::TypeChar: return 2; break; case IntegralType::TypeWchar_t: return 3; break; case IntegralType::TypeInt: if( type->modifiers() & AbstractType::ShortModifier ) return 3; if( type->modifiers() & AbstractType::LongModifier ) return 5; if( type->modifiers() & AbstractType::LongLongModifier ) return 6; return 4; //default-integer //All other types have no integer-conversion-rank default: return 0; }; } bool isIntegerType( const IntegralType::Ptr& type ) { return integerConversionRank(type) != 0; //integerConversionRank returns 0 for non-integer types } bool isFloatingPointType( const IntegralType::Ptr& type ) { return type->dataType() == IntegralType::TypeFloat || type->dataType() == IntegralType::TypeDouble; } bool isVoidType( const AbstractType::Ptr& type ) { IntegralType::Ptr integral = type.cast(); if( !integral ) return false; return integral->dataType() == IntegralType::TypeVoid; } ///Returns whether base is a base-class of c void getMemberFunctions(const StructureType::Ptr& klass, const TopDUContext* topContext, QHash& functions, const QString& functionName, bool mustBeConstant) { Declaration* klassDecl = klass->declaration(topContext); ClassDeclaration* cppClassDecl = dynamic_cast(klassDecl); DUContext* context = klassDecl ? klassDecl->internalContext() : 0; int functionCount = functions.size(); if( context ) { QList declarations = context->findLocalDeclarations(Identifier(functionName), CursorInRevision::invalid(), topContext); for( QList::iterator it = declarations.begin(); it != declarations.end(); ++it ) { KDevelop::FunctionType::Ptr function = (*it)->abstractType().cast(); ClassFunctionDeclaration* functionDeclaration = dynamic_cast( *it ); if( function && functionDeclaration ) { if( !functions.contains(function) && (!mustBeConstant || (function->modifiers() & AbstractType::ConstModifier)) ) { functions[function] = functionDeclaration; } } } } ///One overloaded function of a specific name overloads all inherited with the same name. Think about it in the context where getMemberFunctions is used. if( functionCount != functions.size() ) return; if(cppClassDecl) { //equivalent to using the imported parent-contexts FOREACH_FUNCTION(const KDevelop::BaseClassInstance& base, cppClassDecl->baseClasses) { if( base.access != KDevelop::Declaration::Private ) { //we need const-cast here because the constant list makes also the pointers constant, which is not intended StructureType::Ptr baseClass = base.baseClass.type(); if( baseClass ) getMemberFunctions( baseClass, topContext, functions, functionName, mustBeConstant); } } } } void getMemberFunctions(const StructureType::Ptr& klass, const TopDUContext* topContext, QList& functions, const QString& functionName, bool mustBeConstant) { QHash tempFunctions; getMemberFunctions( klass, topContext, tempFunctions, functionName, mustBeConstant ); for( QHash::const_iterator it = tempFunctions.constBegin(); it != tempFunctions.constEnd(); ++it ) functions << (*it); } void getConstructors(const StructureType::Ptr& klass, const TopDUContext* topContext, QList& functions) { Declaration* klassDecl = klass->declaration(topContext); DUContext* context = klassDecl ? klassDecl->internalContext() : 0; if( !context || !context->owner() || !context->owner() ) { -// kDebug(9007) << "Tried to get constructors of a class without context"; +// qDebug(9007) << "Tried to get constructors of a class without context"; return; } - + Identifier id(context->owner()->identifier()); id.clearTemplateIdentifiers(); QList declarations = context->findLocalDeclarations(id, CursorInRevision::invalid(), topContext, AbstractType::Ptr(), DUContext::OnlyFunctions); for( QList::iterator it = declarations.begin(); it != declarations.end(); ++it ) { ClassFunctionDeclaration* functionDeclaration = dynamic_cast( *it ); if( functionDeclaration && functionDeclaration->isConstructor() ) functions << *it; } } bool isPublicBaseClass( const StructureType::Ptr& c, const StructureType::Ptr& base, const KDevelop::TopDUContext* topContext, int* baseConversionLevels ) { ClassDeclaration* fromDecl = dynamic_cast(c->declaration(topContext)); ClassDeclaration* toDecl = dynamic_cast(base->declaration(topContext)); if(fromDecl && toDecl) return fromDecl->isPublicBaseClass(toDecl, topContext, baseConversionLevels); else return false; } const Identifier& castIdentifier() { static Identifier id("operator{...cast...}"); return id; } KDevelop::AbstractType::Ptr matchingClassPointer(const KDevelop::AbstractType::Ptr& matchTo, const KDevelop::AbstractType::Ptr& actual, const KDevelop::TopDUContext* topContext) { java::TypeConversion conversion(topContext); - + StructureType::Ptr actualStructure = realType(actual, topContext).cast(); - + if(actualStructure) { DUContext* internal = actualStructure->internalContext(topContext); if(internal) { typedef QPair DeclarationDepthPair; foreach(Declaration* decl, internal->findDeclarations(castIdentifier(), CursorInRevision::invalid(), topContext, (DUContext::SearchFlags)(DUContext::DontSearchInParent | DUContext::NoFiltering))) { FunctionType::Ptr funType = decl->type(); if(funType && funType->returnType()) { if(conversion.implicitConversion(funType->returnType()->indexed(), matchTo->indexed(), true)) { return funType->returnType(); } } } } } - + return actual; } Declaration* getDeclaration( const AbstractType::Ptr& type, TopDUContext* top ) { if( !type) return 0; - const IdentifiedType* idType = dynamic_cast(type.unsafeData()); + const IdentifiedType* idType = dynamic_cast(type.data()); if( idType ) { return idType->declaration(top); } else { return 0; } } AbstractType::Ptr decreasePointerDepth(AbstractType::Ptr type, TopDUContext* top, bool useOperator) { type = realType(type, top); - + if( PointerType::Ptr pt = type.cast() ) { //Dereference return pt->baseType(); }else if( ArrayType::Ptr pt = type.cast() ) { return pt->elementType(); }else{ if(useOperator) { Declaration* decl = getDeclaration(type, top); if(decl && decl->internalContext()) { QList decls = decl->internalContext()->findDeclarations(Identifier("operator*"), CursorInRevision::invalid(), top, DUContext::DontSearchInParent); if(!decls.isEmpty()) { FunctionType::Ptr fun = decls.first()->type(); if(fun) return fun->returnType(); } } } } return AbstractType::Ptr(); } AbstractType::Ptr increasePointerDepth(AbstractType::Ptr type) { AbstractType::Ptr oldType = realType(type, 0); ///Dereference references PointerType::Ptr newPointer(new PointerType()); newPointer->setBaseType( oldType ); return newPointer.cast(); } AbstractType::Ptr removeConstants(AbstractType::Ptr type) { if(ConstantIntegralType::Ptr integral = type.cast()) return AbstractType::Ptr(new IntegralType(*integral)); - + return type; } } diff --git a/duchain/usebuilder.cpp b/duchain/usebuilder.cpp index 609e3b4..fc092c4 100644 --- a/duchain/usebuilder.cpp +++ b/duchain/usebuilder.cpp @@ -1,82 +1,82 @@ /* This file is part of KDevelop Copyright 2006-2008 Hamish Rodda 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. */ #include "usebuilder.h" #include "editorintegrator.h" #include "parsesession.h" using namespace KTextEditor; using namespace KDevelop; namespace java { class UseBuilder::UseExpressionVisitor : public ExpressionVisitor { public: UseExpressionVisitor ( EditorIntegrator* editor, UseBuilder* builder ); protected: virtual void usingDeclaration ( AstNode* node, qint64 start_token, qint64 end_token, const KDevelop::DeclarationPointer& decl ) override; private: UseBuilder* m_builder; }; UseBuilder::UseBuilder (ParseSession* session) { setEditor(session); } UseBuilder::UseBuilder (EditorIntegrator* editor) { setEditor(editor); } void UseBuilder::visitPrimaryExpression(PrimaryExpressionAst* node) { UseExpressionVisitor visitor( editor(), this ); if ( !node->ducontext ) node->ducontext = currentContext(); visitor.parse(node); } void UseBuilder::visitClassOrInterfaceTypeName(ClassOrInterfaceTypeNameAst* node) { UseExpressionVisitor visitor( editor(), this ); if ( !node->ducontext ) node->ducontext = currentContext(); visitor.parse( node ); } UseBuilder::UseExpressionVisitor::UseExpressionVisitor ( EditorIntegrator* editor, UseBuilder* builder ) : ExpressionVisitor ( editor ) { m_builder = builder; } void UseBuilder::UseExpressionVisitor::usingDeclaration( AstNode* node, qint64 start_token, qint64 end_token, const KDevelop::DeclarationPointer& decl ) { if (start_token == qint64()) start_token = node->startToken; if (end_token == qint64()) end_token = node->endToken; - kDebug() << "New use" << editor()->findRange(start_token, end_token) << " declaration" << decl.data() << decl->toString(); - m_builder->newUse(node, editor()->findRange(start_token, end_token), decl); + qDebug() << "New use" << editor()->findRange(start_token, end_token) << " declaration" << decl.data() << decl->toString(); + m_builder->newUse(editor()->findRange(start_token, end_token), decl); } } diff --git a/duchain/usebuilder.h b/duchain/usebuilder.h index e80fbae..f1fbea1 100644 --- a/duchain/usebuilder.h +++ b/duchain/usebuilder.h @@ -1,54 +1,54 @@ /* This file is part of KDevelop Copyright 2006-2008 Hamish Rodda 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. */ #ifndef USEBUILDER_H #define USEBUILDER_H #include #include "expressionvisitor.h" -#include "javaduchainexport.h" +#include "javaduchain_export.h" namespace java { class ParseSession; typedef KDevelop::AbstractUseBuilder UseBuilderBase; /** * A class which iterates the AST to extract uses of definitions. */ class KDEVJAVADUCHAIN_EXPORT UseBuilder: public UseBuilderBase { public: UseBuilder(ParseSession* session); UseBuilder(EditorIntegrator* editor); protected: private: virtual void visitClassOrInterfaceTypeName(ClassOrInterfaceTypeNameAst* node) override; virtual void visitPrimaryExpression(PrimaryExpressionAst* node) override; class UseExpressionVisitor; }; } #endif // USEBUILDER_H diff --git a/duchain/viablefunctions.cpp b/duchain/viablefunctions.cpp index 4ab4843..795e3ab 100644 --- a/duchain/viablefunctions.cpp +++ b/duchain/viablefunctions.cpp @@ -1,164 +1,164 @@ /* This file is part of KDevelop Copyright 2007 David Nolden 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. */ #include "viablefunctions.h" #include #include #include #include #include "typeutils.h" #include "typeconversion.h" using namespace java; ///@todo prefer more specialized template-functions above less specialized ones inline bool ViableFunction::ParameterConversion::operator<(const ParameterConversion& rhs) const { if( rank < rhs.rank ) return true; else if( rank > rhs.rank ) return false; else return baseConversionLevels > rhs.baseConversionLevels; //Conversion-rank is same, so use the base-conversion levels for ranking } ViableFunction::ViableFunction( TopDUContext* topContext, Declaration* decl, bool noUserDefinedConversion ) : m_declaration(decl), m_topContext(topContext), m_type(0), m_parameterCountMismatch(true), m_noUserDefinedConversion(noUserDefinedConversion) { if( decl ) m_type = decl->abstractType().cast(); m_funDecl = dynamic_cast(m_declaration.data()); } KDevelop::DeclarationPointer ViableFunction::declaration() const { return m_declaration; } bool ViableFunction::isValid() const { return m_type && m_declaration && m_funDecl; } void ViableFunction::matchParameters( const OverloadResolver::ParameterList& params, bool partial ) { if( !isValid() || !m_topContext ) return; Q_ASSERT(m_funDecl); uint functionArgumentCount = m_type->indexedArgumentsSize(); if( params.parameters.size() + m_funDecl->defaultParametersSize() < functionArgumentCount && !partial ) { - //kDebug() << "Not enough parameters + default-parameters"; + //qDebug() << "Not enough parameters + default-parameters"; return; //Not enough parameters + default-parameters } if( params.parameters.size() > functionArgumentCount ) { - //kDebug() << "Too many parameters" << params.parameters.size() << "gt" << functionArgumentCount; + //qDebug() << "Too many parameters" << params.parameters.size() << "gt" << functionArgumentCount; return; //Too many parameters } m_parameterCountMismatch = false; //Match all parameters against the argument-type const IndexedType* arguments = m_type->indexedArguments(); const IndexedType* argumentIt = arguments; TypeConversion conv(m_topContext.data()); for( QList::const_iterator it = params.parameters.begin(); it != params.parameters.end(); ++it ) { ParameterConversion c; /* MissingDeclarationType::Ptr missing = (*argumentIt).type(); if(missing) { missing->convertedTo.type = (*it).type->indexed(); }else{*/ c.rank = conv.implicitConversion( (*it).type->indexed(), *argumentIt, (*it).lValue, m_noUserDefinedConversion ); c.baseConversionLevels = conv.baseConversionLevels(); // } m_parameterConversions << c; ++argumentIt; } } bool ViableFunction::operator< ( const ViableFunction& other ) const { return isBetter(other); } bool ViableFunction::isBetter( const ViableFunction& other ) const { if( !isViable() ) return false; if( !other.isViable() ) return true; ///iso c++ 13.3.3 - best viable function //Is one of our conversions worse than one of the other function's? uint minParams = m_parameterConversions.size(); if(other.m_parameterConversions.size() < minParams) minParams = other.m_parameterConversions.size(); bool hadBetterConversion = false; for(int a = 0; a < minParams; ++a) { if( m_parameterConversions[a] < other.m_parameterConversions[a] ) return false; //All this function's conversions must not be worse than the other function one's if( other.m_parameterConversions[a] < m_parameterConversions[a] ) hadBetterConversion = true; } ///@todo any special measures when parameter-counts differ? if( hadBetterConversion ) return true; /**Until now both functions have the same match-quality. Iso c++ says this is better when: * - this is a non-template function while other is one * - this is a template-function that is more specialized than other */ // Java commented out for now //if(!dynamic_cast(m_declaration.data()) && dynamic_cast(other.m_declaration.data())) //return true; // preexisting comment out // if( m_type->isMoreSpecialized( other.m_type.data() ) ) // return true; return false; } bool ViableFunction::isViable() const { if( !isValid() || m_parameterCountMismatch ) return false; for( int a = 0; a < m_parameterConversions.size(); ++a ) if( !m_parameterConversions[a].rank ) return false; return true; } uint ViableFunction::worstConversion() const { uint ret = (uint)-1; for( int a = 0; a < m_parameterConversions.size(); ++a ) if( (uint) m_parameterConversions[a].rank < ret ) ret *= m_parameterConversions[a].rank; if( ret == (uint)-1 ) return 0; else return ret; } const KDevVarLengthArray& ViableFunction::parameterConversions() const { return m_parameterConversions; } diff --git a/javalanguagesupport.cpp b/javalanguagesupport.cpp index 562eb82..3385834 100644 --- a/javalanguagesupport.cpp +++ b/javalanguagesupport.cpp @@ -1,180 +1,189 @@ /* This file is part of KDevelop Copyright (C) 2006 Adam Treat Copyright (C) 2008 Hamish Rodda 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 "javalanguagesupport.h" #include -#include -#include -#include -#include -#include +#include -#include -#include +#include +#include #include #include #include #include #include #include #include #include #include "parsejob.h" +#include "settings/javapreferences.h" #include #include #include "completion/model.h" #include #include -#include #include #include #include -#include #include #include using namespace java; -K_PLUGIN_FACTORY(KDevJavaSupportFactory, registerPlugin(); ) -K_EXPORT_PLUGIN(KDevJavaSupportFactory("kdevjavasupport")) +K_PLUGIN_FACTORY_WITH_JSON(KDevJavaSupportFactory, "kdevjavasupport.json", registerPlugin(); ) JavaLanguageSupport* JavaLanguageSupport::s_self = 0; JavaLanguageSupport::JavaLanguageSupport( QObject* parent, const QVariantList& /*args*/ ) - : KDevelop::IPlugin( KDevJavaSupportFactory::componentData(), parent ) + : KDevelop::IPlugin(QStringLiteral("kdevjavasupport"), parent ) , KDevelop::ILanguageSupport() , m_allJavaContext(0) , m_javaSourceZipMutex(new QMutex()) , m_javaSourceZip(0) { s_self = this; - - KDEV_USE_EXTENSION_INTERFACE( KDevelop::ILanguageSupport ) m_highlighting = new KDevelop::CodeHighlighting( this ); CodeCompletionModel* ccModel = new CodeCompletionModel(this); new KDevelop::CodeCompletion( this, ccModel, name() ); scheduleInternalSources(); - kDebug() << "Java support loaded"; + qDebug() << "Java support loaded"; } JavaLanguageSupport::~JavaLanguageSupport() { - KDevelop::ILanguage* lang = language(); + KDevelop::ILanguageSupport* lang = language(); if (lang) { lang->parseLock()->lockForWrite(); s_self = 0; //By locking the parse-mutexes, we make sure that parse- and preprocess-jobs get a chance to finish in a good state lang->parseLock()->unlock(); } delete m_javaSourceZip; } JavaLanguageSupport* JavaLanguageSupport::self() { return s_self; } KDevelop::ParseJob *JavaLanguageSupport::createParseJob( const KDevelop::IndexedString& url ) { return new ParseJob( url, this ); } QString JavaLanguageSupport::name() const { return "Java"; } -KDevelop::ILanguage * JavaLanguageSupport::language() +KDevelop::ILanguageSupport * JavaLanguageSupport::language() { return core()->languageController()->language(name()); } void JavaLanguageSupport::scheduleInternalSources() { - KConfigGroup config(KGlobal::config(), "Java Support"); - m_javaSourceUrl = config.readEntry("Java Source Zip", KUrl()); + KConfigGroup config(KSharedConfig::openConfig(), "Java Support"); + m_javaSourceUrl = config.readEntry("Java Source Zip", QUrl()); - if (m_javaSourceUrl.protocol() == "file") { + if (m_javaSourceUrl.scheme() == "file") { // KIO method - replace with KZip method if you can understand the KArchive API QFileInfo info(m_javaSourceUrl.path()); if (info.exists() && info.isReadable() && info.isFile()) { m_javaSourceZip = new KZip(m_javaSourceUrl.path()); if (!m_javaSourceZip->open(QIODevice::ReadOnly)) { - kDebug() << "error, could not open zip file"<< m_javaSourceUrl <<"for reading."; + qDebug() << "error, could not open zip file"<< m_javaSourceUrl <<"for reading."; return; } - m_javaSourceUrl.setProtocol("zip"); - m_javaSourceUrl.adjustPath(KUrl::AddTrailingSlash); + m_javaSourceUrl.setScheme("zip"); + + QString path = m_javaSourceUrl.path(); + if (path.length() > 0 && path.back() != QLatin1Char('/')) { + m_javaSourceUrl.setPath(path + QLatin1Char('/')); + } + KIO::ListJob* list = KIO::listRecursive(m_javaSourceUrl, KIO::DefaultFlags, false); connect(list, SIGNAL(entries(KIO::Job*,KIO::UDSEntryList)), SLOT(slotJavaSourceEntries(KIO::Job*,KIO::UDSEntryList))); list->start(); } else { - kDebug() << m_javaSourceUrl << "error, file doesn't exist or is not readable"; + qDebug() << m_javaSourceUrl << "error, file doesn't exist or is not readable"; } } else { - kDebug() << m_javaSourceUrl << "error, non file protocol url"; + qDebug() << m_javaSourceUrl << "error, non file protocol url"; } } void JavaLanguageSupport::slotJavaSourceEntries(KIO::Job* job, KIO::UDSEntryList entries) { Q_UNUSED(job); - + foreach (KIO::UDSEntry entry, entries) { - KUrl url = m_javaSourceUrl; - url.addPath(entry.stringValue(KIO::UDSEntry::UDS_NAME)); + QUrl url = m_javaSourceUrl; + url = url.adjusted(QUrl::StripTrailingSlash); + url.setPath(url.path() + '/' + (entry.stringValue(KIO::UDSEntry::UDS_NAME))); if (!entry.isDir() && !entry.isLink()) { - kDebug() << "Found" << url << "in the java source zip, scheduled for parsing"; + qDebug() << "Found" << url << "in the java source zip, scheduled for parsing"; KDevelop::ICore::self()->languageController()->backgroundParser()->addDocument(KDevelop::IndexedString(url), KDevelop::TopDUContext::SimplifiedVisibleDeclarationsAndContexts); } } } KZip* JavaLanguageSupport::javaSourceZip() const -{ +{ return m_javaSourceZip; } QMutex* JavaLanguageSupport::javaSourceZipMutex() const { return m_javaSourceZipMutex; } KDevelop::ICodeHighlighting* JavaLanguageSupport::codeHighlighting() const { return m_highlighting; } +KDevelop::ConfigPage* JavaLanguageSupport::configPage(int number, QWidget* parent) +{ + return number == 0 ? new JavaPreferences(parent) : nullptr; +} + +int JavaLanguageSupport::configPages() const +{ + return 1; +} + + #include "javalanguagesupport.moc" // kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on diff --git a/javalanguagesupport.h b/javalanguagesupport.h index 18ede58..15b9b18 100644 --- a/javalanguagesupport.h +++ b/javalanguagesupport.h @@ -1,85 +1,88 @@ /* This file is part of KDevelop Copyright (C) 2006 Adam Treat Copyright (C) 2008 Hamish Rodda 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. */ #ifndef KDEVJAVALANGUAGESUPPORT_H #define KDEVJAVALANGUAGESUPPORT_H #include #include #include #include #include #include #include class KJob; class KZip; namespace KIO { class Job; } namespace KDevelop { class IDocument; class IProject; class DUContext; class CodeHighlighting; } class JavaLanguageSupport : public KDevelop::IPlugin, public KDevelop::ILanguageSupport { Q_OBJECT Q_INTERFACES( KDevelop::ILanguageSupport ) public: JavaLanguageSupport( QObject* parent, const QVariantList& args = QVariantList() ); virtual ~JavaLanguageSupport(); - virtual QString name() const; + virtual QString name() const override; - virtual KDevelop::ParseJob *createParseJob(const KDevelop::IndexedString& url); - virtual KDevelop::ILanguage *language(); - virtual KDevelop::ICodeHighlighting* codeHighlighting() const; + virtual KDevelop::ParseJob *createParseJob(const KDevelop::IndexedString& url) override; + virtual KDevelop::ILanguageSupport *language(); + virtual KDevelop::ICodeHighlighting* codeHighlighting() const override; + + KDevelop::ConfigPage* configPage(int number, QWidget *parent) override; + int configPages() const override; static JavaLanguageSupport* self(); QMutex* javaSourceZipMutex() const; KZip* javaSourceZip() const; private Q_SLOTS: void slotJavaSourceEntries(KIO::Job* job, KIO::UDSEntryList entries); - + private: void scheduleInternalSources(); KDevelop::CodeHighlighting* m_highlighting; KDevelop::ReferencedTopDUContext m_allJavaContext; - KUrl m_javaSourceUrl; + QUrl m_javaSourceUrl; QMutex* m_javaSourceZipMutex; mutable KZip* m_javaSourceZip; - + static JavaLanguageSupport* s_self; }; #endif // kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on diff --git a/kdevjavasupport.desktop.cmake b/kdevjavasupport.desktop.cmake deleted file mode 100644 index 9bd8752..0000000 --- a/kdevjavasupport.desktop.cmake +++ /dev/null @@ -1,100 +0,0 @@ -[Desktop Entry] -Encoding=UTF-8 -Type=Service -Exec=blubb -Comment=Java Language Support -Comment[ast]=Sofitu de llinguax Java -Comment[bg]=Поддръжка на езика Java -Comment[bs]=Podrška za jezik Java -Comment[ca]=Implementació de llenguatge Java -Comment[ca@valencia]=Implementació de llenguatge Java -Comment[de]=Sprachunterstützung für Java -Comment[el]=Υποστήριξη γλώσσας Java -Comment[en_GB]=Java Language Support -Comment[es]=Implementación de lenguaje Java -Comment[et]=Java keele toetus -Comment[fi]=Java-kielituki -Comment[fr]=Prise en charge du langage Java -Comment[ga]=Tacaíocht Java -Comment[gl]=Soporte de Java -Comment[hne]=जावा भाखा समर्थन -Comment[hu]=Java nyelvi támogatás -Comment[it]=Supporto per il linguaggio Java -Comment[ja]=Java 言語のサポート -Comment[nds]=Ünnerstütten för Java -Comment[nl]=Ondersteuning voor de Java-taal -Comment[pa]=ਜਾਵਾ ਲੈਗੂਇਜ਼ ਸਹਿਯੋਗ -Comment[pl]=Obsługa języka Java -Comment[pt]=Suporte para a Linguagem Java -Comment[pt_BR]=Suporte à linguagem Java -Comment[sk]=Podpora jazyka Java -Comment[sv]=Stöd för språket Java -Comment[tr]=Java Dil Desteği -Comment[uk]=Підтримка мови Java -Comment[x-test]=xxJava Language Supportxx -Name=Java Support -Name[bg]=Поддръжка на Java -Name[bs]=Podrška za jezik Java -Name[ca]=Implementació Java -Name[ca@valencia]=Implementació Java -Name[de]=Unterstützung für Java -Name[en_GB]=Java Support -Name[es]=Implementación de Java -Name[et]=Java toetus -Name[fi]=Java-tuki -Name[fr]=Prise en charge de Java -Name[ga]=Tacaíocht Java -Name[gl]=Soporte de Java -Name[hu]=Java támogatás -Name[it]=Supporto per Java -Name[ja]=Java サポート -Name[nds]=Java-Ünnerstütten -Name[nl]=Ondersteuning voor Java -Name[pa]=ਜਾਵਾ ਸਹਿਯੋਗ -Name[pl]=Obsługa Java -Name[pt]=Suporte para Java -Name[pt_BR]=Suporte a Java -Name[sk]=Podpora Javy -Name[sv]=Java-stöd -Name[tr]=Java Desteği -Name[uk]=Підтримка Java -Name[x-test]=xxJava Supportxx -GenericName=Java Support -GenericName[bg]=Поддръжка на Java -GenericName[bs]=Podrška za jezik Java -GenericName[ca]=Implementació Java -GenericName[ca@valencia]=Implementació Java -GenericName[de]=Unterstützung für Java -GenericName[el]=Υποστήριξη Java -GenericName[en_GB]=Java Support -GenericName[es]=Implementación Java -GenericName[et]=Java toetus -GenericName[fi]=Java-tuki -GenericName[fr]=Prise en charge de Java -GenericName[ga]=Tacaíocht Java -GenericName[gl]=Soporte de Java -GenericName[hne]=जावा समर्थन -GenericName[hu]=Java támogatás -GenericName[it]=Supporto per Java -GenericName[ja]=Java サポート -GenericName[nds]=Java-Ünnerstütten -GenericName[nl]=Ondersteuning voor Java -GenericName[pa]=ਜਾਵਾ ਸਹਿਯੋਗ -GenericName[pl]=Obsługa Java -GenericName[pt]=Suporte para Java -GenericName[pt_BR]=Suporte a Java -GenericName[sk]=Podpora Javy -GenericName[sv]=Java-stöd -GenericName[tr]=Java Desteği -GenericName[uk]=Підтримка Java -GenericName[x-test]=xxJava Supportxx -ServiceTypes=KDevelop/Plugin -Icon=application-x-java -X-KDE-Library=kdevjavalanguagesupport -X-KDevelop-Version=@KDEV_PLUGIN_VERSION@ -X-KDevelop-Language=Java -X-KDevelop-Interfaces=ILanguageSupport -X-KDevelop-SupportedMimeTypes=text/x-java -X-KDE-PluginInfo-Name=kdevjavasupport -X-KDevelop-Mode=NoGUI -X-KDE-PluginInfo-Category=Language Support diff --git a/kdevjavasupport.json b/kdevjavasupport.json new file mode 100644 index 0000000..910c602 --- /dev/null +++ b/kdevjavasupport.json @@ -0,0 +1,76 @@ +{ + "KPlugin": { + "Category": "Language Support", + "Description": "Java Language Support", + "Description[ast]": "Sofitu de llinguax Java", + "Description[bg]": "Поддръжка на езика Java", + "Description[bs]": "Podrška za jezik Java", + "Description[ca@valencia]": "Implementació de llenguatge Java", + "Description[ca]": "Implementació de llenguatge Java", + "Description[de]": "Sprachunterstützung für Java", + "Description[el]": "Υποστήριξη γλώσσας Java", + "Description[en_GB]": "Java Language Support", + "Description[es]": "Implementación de lenguaje Java", + "Description[et]": "Java keele toetus", + "Description[fi]": "Java-kielituki", + "Description[fr]": "Prise en charge du langage Java", + "Description[ga]": "Tacaíocht Java", + "Description[gl]": "Soporte de Java", + "Description[hne]": "जावा भाखा समर्थन", + "Description[hu]": "Java nyelvi támogatás", + "Description[it]": "Supporto per il linguaggio Java", + "Description[ja]": "Java 言語のサポート", + "Description[nds]": "Ünnerstütten för Java", + "Description[nl]": "Ondersteuning voor de Java-taal", + "Description[pa]": "ਜਾਵਾ ਲੈਗੂਇਜ਼ ਸਹਿਯੋਗ", + "Description[pl]": "Obsługa języka Java", + "Description[pt]": "Suporte para a Linguagem Java", + "Description[pt_BR]": "Suporte à linguagem Java", + "Description[sk]": "Podpora jazyka Java", + "Description[sv]": "Stöd för språket Java", + "Description[tr]": "Java Dil Desteği", + "Description[uk]": "Підтримка мови Java", + "Description[x-test]": "xxJava Language Supportxx", + "Icon": "application-x-java", + "Id": "kdevjavasupport", + "License": "GPL", + "Name": "Java Support", + "Name[bg]": "Поддръжка на Java", + "Name[bs]": "Podrška za jezik Java", + "Name[ca@valencia]": "Implementació Java", + "Name[ca]": "Implementació Java", + "Name[de]": "Unterstützung für Java", + "Name[en_GB]": "Java Support", + "Name[es]": "Implementación de Java", + "Name[et]": "Java toetus", + "Name[fi]": "Java-tuki", + "Name[fr]": "Prise en charge de Java", + "Name[ga]": "Tacaíocht Java", + "Name[gl]": "Soporte de Java", + "Name[hu]": "Java támogatás", + "Name[it]": "Supporto per Java", + "Name[ja]": "Java サポート", + "Name[nds]": "Java-Ünnerstütten", + "Name[nl]": "Ondersteuning voor Java", + "Name[pa]": "ਜਾਵਾ ਸਹਿਯੋਗ", + "Name[pl]": "Obsługa Java", + "Name[pt]": "Suporte para Java", + "Name[pt_BR]": "Suporte a Java", + "Name[sk]": "Podpora Javy", + "Name[sv]": "Java-stöd", + "Name[tr]": "Java Desteği", + "Name[uk]": "Підтримка Java", + "Name[x-test]": "xxJava Supportxx", + "ServiceTypes": [ + "KDevelop/Plugin" + ] + }, + "X-KDevelop-Interfaces": [ + "ILanguageSupport" + ], + "X-KDevelop-Language": "Java", + "X-KDevelop-Mode": "NoGUI", + "X-KDevelop-SupportedMimeTypes": [ + "text/x-java" + ] +} diff --git a/parsejob.cpp b/parsejob.cpp index 7699057..8a9530d 100644 --- a/parsejob.cpp +++ b/parsejob.cpp @@ -1,270 +1,262 @@ /* * This file is part of KDevelop * * Copyright (c) 2006 Adam Treat * Copyright (c) 2006 Jakob Petsovits * Copyright (C) 2008 Hamish Rodda * * This program 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 program 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "parsejob.h" #include #include #include -#include "Thread.h" - #include #include #include #include - -#include -#include +#include #include "javalanguagesupport.h" // from the parser subdirectory #include #include #include -#include #include #include "parser/dumptree.h" #include #include #include "duchain/declarationbuilder.h" #include "duchain/usebuilder.h" #include "duchain/editorintegrator.h" #include "duchain/dumpchain.h" #include #include #include #include -#include #include #include #include #include namespace java { ParseJob::ParseJob( const KDevelop::IndexedString &url, KDevelop::ILanguageSupport* languageSupport) : KDevelop::ParseJob( url, languageSupport ) , m_session( new ParseSession ) , m_readFromDisk( false ) {} ParseJob::~ParseJob() { delete m_session; } JavaLanguageSupport* ParseJob::java() const { return JavaLanguageSupport::self(); } ParseSession *ParseJob::parseSession() const { return m_session; } bool ParseJob::wasReadFromDisk() const { return m_readFromDisk; } void ParseJob::run() { if ( abortRequested() ) return abortJob(); - KUrl fileUrl(document().str()); + QUrl fileUrl(document().str()); if ( !(minimumFeatures() & KDevelop::TopDUContext::ForceUpdate) ) { bool needsUpdate = true; KDevelop::DUChainReadLocker lock; ///TODO: this is hacky - we check for any env file for a zipped file and assume it's up2date /// updating a zip file won't trigger reparsing though... - bool isZipFile = fileUrl.protocol() == "zip"; + bool isZipFile = fileUrl.scheme() == "zip"; foreach(const KDevelop::ParsingEnvironmentFilePointer &file, KDevelop::DUChain::self()->allEnvironmentFiles(document())) { if (file->needsUpdate() && !(isZipFile && file->featuresSatisfied(minimumFeatures()))) { needsUpdate = true; break; } else { needsUpdate = false; } } if (!needsUpdate) { - kDebug() << "Already up to date" << document().str(); + qDebug() << "Already up to date" << document().str(); return; } } if ( abortRequested() ) return abortJob(); KDevelop::ProblemPointer p = readContents(); if (p) return abortJob(); m_session->setContents(contents().contents); QReadLocker lock(java()->language()->parseLock()); - kDebug() << "===-- PARSING --===> " + qDebug() << "===-- PARSING --===> " << document().str() << " <== readFromDisk: " << m_readFromDisk << " size: " << m_session->size(); if ( abortRequested() ) return abortJob(); // 0) setup java::Parser javaParser; javaParser.setCompatibilityMode( m_session->compatibilityMode ); javaParser.setTokenStream( m_session->tokenStream ); javaParser.setMemoryPool( m_session->memoryPool ); // 1) tokenize javaParser.tokenize( (char*) m_session->contents() ); if ( abortRequested() ) return abortJob(); // 2) parse CompilationUnitAst *ast = 0; bool matched = javaParser.parseCompilationUnit( &ast ); if ( abortRequested() ) return abortJob(); if ( matched ) { DefaultVisitor v; v.visitNode( ast ); } else { // FIXME //java_parser.yy_expected_symbol(AstNode::Kind_compilation_unit, "compilation_unit"); // ### remove me } // 3) Form definition-use chain m_session->m_document = document(); java::EditorIntegrator editor(parseSession()); - //kDebug( ) << (contentContext ? "updating" : "building") << "duchain for" << parentJob()->document().str(); + //qDebug( ) << (contentContext ? "updating" : "building") << "duchain for" << parentJob()->document().str(); // TODO: use zip hash to find out if jdk/other source has changed when going for 2nd pass KDevelop::ReferencedTopDUContext toUpdate; { KDevelop::DUChainReadLocker lock; toUpdate = KDevelop::DUChainUtils::standardContextForUrl(document().toUrl()); } KDevelop::TopDUContext::Features newFeatures = minimumFeatures(); if (toUpdate) newFeatures = (KDevelop::TopDUContext::Features)(newFeatures | toUpdate->features()); if (newFeatures & KDevelop::TopDUContext::ForceUpdate) - kDebug() << "update enforced"; + qDebug() << "update enforced"; //Remove update-flags like 'Recursive' or 'ForceUpdate' newFeatures = static_cast(newFeatures & KDevelop::TopDUContext::AllDeclarationsContextsUsesAndAST); DeclarationBuilder declarationBuilder(&editor); if (newFeatures == KDevelop::TopDUContext::SimplifiedVisibleDeclarationsAndContexts) { declarationBuilder.setOnlyComputeVisible(true); //Only visible declarations/contexts need to be built. declarationBuilder.setBuildCompleteTypes(false); - + } else if (newFeatures == KDevelop::TopDUContext::VisibleDeclarationsAndContexts) { declarationBuilder.setOnlyComputeVisible(true); //Only visible declarations/contexts need to be built. } - + KDevelop::TopDUContext* chain = declarationBuilder.build(document(), ast, toUpdate); setDuChain(chain); - + bool declarationsComplete = !declarationBuilder.hadUnresolvedIdentifiers(); - kDebug() << "Parsing with feature set: " << newFeatures << " complete:" <languageController()->backgroundParser()->addDocument(KDevelop::IndexedString(fileUrl), static_cast(newFeatures | KDevelop::TopDUContext::VisibleDeclarationsAndContexts), 10000); } else { // We haven't resolved all identifiers, but by now, we don't expect to - kDebug() << "Builder found unresolved identifiers when they should have been resolved! (if there was no coding error)"; + qDebug() << "Builder found unresolved identifiers when they should have been resolved! (if there was no coding error)"; declarationsComplete = true; } } } if (declarationsComplete && (newFeatures & KDevelop::TopDUContext::AllDeclarationsContextsAndUses) == KDevelop::TopDUContext::AllDeclarationsContextsAndUses) { - kDebug() << "Building uses"; + qDebug() << "Building uses"; UseBuilder useBuilder(&editor); useBuilder.buildUses(ast); } if (!abortRequested()) { if ( java()->codeHighlighting() ) { java()->codeHighlighting()->highlightDUChain( duChain() ); } } if (declarationsComplete && (newFeatures & KDevelop::TopDUContext::AllDeclarationsContextsAndUses) == KDevelop::TopDUContext::AllDeclarationsContextsAndUses) { DumpChain dump; dump.dump(ast, m_session); - + KDevelop::DUChainReadLocker duchainlock(KDevelop::DUChain::lock()); dump.dump(chain); } } } // end of namespace java -#include "parsejob.moc" - // kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on diff --git a/parsejob.h b/parsejob.h index 1c9bda7..b14e277 100644 --- a/parsejob.h +++ b/parsejob.h @@ -1,67 +1,67 @@ /* * This file is part of KDevelop * * Copyright (c) 2006 Adam Treat * Copyright (c) 2006 Jakob Petsovits * Copyright (C) 2008 Hamish Rodda * * This program 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 program 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef JAVA_PARSEJOB_H #define JAVA_PARSEJOB_H -#include +#include #include // from the parser subdirectory #include class JavaLanguageSupport; namespace java { class ParseSession; class ParseJob : public KDevelop::ParseJob { Q_OBJECT public: ParseJob( const KDevelop::IndexedString &url, KDevelop::ILanguageSupport* languageSupport ); virtual ~ParseJob(); JavaLanguageSupport* java() const; ParseSession* parseSession() const; bool wasReadFromDisk() const; protected: virtual void run(); private: ParseSession *m_session; bool m_readFromDisk; }; } // end of namespace java #endif diff --git a/parser/CMakeLists.txt b/parser/CMakeLists.txt index cc35848..f86911b 100644 --- a/parser/CMakeLists.txt +++ b/parser/CMakeLists.txt @@ -1,79 +1,77 @@ include_directories( - ${KDE4_INCLUDES} - ${KDE4_INCLUDE_DIR}/kdevelop-pg-qt ${CMAKE_CURRENT_SOURCE_DIR} - ${KDEVPLATFORM_INCLUDE_DIR} # ${KDEVPLATFORM_INCLUDE_DIR}/interfaces # ${KDEVPLATFORM_INCLUDE_DIR}/editor # ${KDEVPLATFORM_INCLUDE_DIR}/project # ${KDEVPLATFORM_INCLUDE_DIR}/project/interfaces # ${KDEVPLATFORM_INCLUDE_DIR}/language # ${KDEVPLATFORM_INCLUDE_DIR}/language/interfaces # ${KDEVPLATFORM_INCLUDE_DIR}/language/backgroundparser # ${KDEVPLATFORM_INCLUDE_DIR}/language/duchain # ${KDEVPLATFORM_INCLUDE_DIR}/language/duchain/viewer ) ########### next target ############### # autogenerate the lexer and the parser kdevpgqt_generate(_kdevpgList java NAMESPACE java DEBUG_VISITOR "${CMAKE_CURRENT_SOURCE_DIR}/java.g" "${CMAKE_CURRENT_SOURCE_DIR}/javalexer.h" ) set(kdevjavaparser_STAT_SRCS java_io.cpp parsesession.cpp dumptree.cpp ${_kdevpgList} ) -find_package(Flex REQUIRED) +find_package(FLEX REQUIRED) # Copy javalexer.ll to the builddir, so that flex doesn't write out # absolute paths in the generated file when we pass them as arguments. # In short, I don't want stuff like # '#line 2 "/home/kde/build/.../javalexer.cpp" in SVN. add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/javalexer.ll" MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/javalexer.ll" COMMAND ${CMAKE_COMMAND} ARGS -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/javalexer.ll" "${CMAKE_CURRENT_BINARY_DIR}/javalexer.ll" ) set_source_files_properties( "${CMAKE_CURRENT_BINARY_DIR}/javalexer.ll" GENERATED ) # Add command to generate the lexer. add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/javalexer.cpp" MAIN_DEPENDENCY "${CMAKE_CURRENT_BINARY_DIR}/javalexer.ll" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/javaparser.h" COMMAND ${FLEX_EXECUTABLE} ARGS -o"javalexer.cpp" "javalexer.ll" WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) set(kdevjavaparser_STAT_SRCS ${kdevjavaparser_STAT_SRCS} "${CMAKE_CURRENT_BINARY_DIR}/javalexer.cpp" ) set_source_files_properties( "${CMAKE_CURRENT_BINARY_DIR}/javalexer.cpp" GENERATED ) # Note: This library doesn't follow API/ABI/BC rules and shouldn't have a SOVERSION # Its only purpose is to support the plugin without needing to add all source files # to the plugin target -kde4_add_library(kdev4javaparser SHARED ${kdevjavaparser_STAT_SRCS}) -target_link_libraries(kdev4javaparser ${KDE4_KDECORE_LIBS} ${KDE4_KTEXTEDITOR_LIBS} ${KDEVPLATFORM_LANGUAGE_LIBRARIES}) -install(TARGETS kdev4javaparser ${INSTALL_TARGETS_DEFAULT_ARGS} ) +add_library(kdev4javaparser SHARED ${kdevjavaparser_STAT_SRCS}) +generate_export_header(kdev4javaparser BASE_NAME javaparser EXPORT_MACRO_NAME KDEVJAVAPARSER_EXPORT) +target_link_libraries(kdev4javaparser KDev::Util) +install(TARGETS kdev4javaparser ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/parser/FlexLexer.h b/parser/FlexLexer.h deleted file mode 100644 index 9268b13..0000000 --- a/parser/FlexLexer.h +++ /dev/null @@ -1,208 +0,0 @@ - -// -*-C++-*- -// FlexLexer.h -- define interfaces for lexical analyzer classes generated -// by flex - -// Copyright (c) 1993 The Regents of the University of California. -// All rights reserved. -// -// This code is derived from software contributed to Berkeley by -// Kent Williams and Tom Epperly. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: - -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. - -// Neither the name of the University nor the names of its contributors -// may be used to endorse or promote products derived from this software -// without specific prior written permission. - -// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE. - -// This file defines FlexLexer, an abstract class which specifies the -// external interface provided to flex C++ lexer objects, and yyFlexLexer, -// which defines a particular lexer class. -// -// If you want to create multiple lexer classes, you use the -P flag -// to rename each yyFlexLexer to some other xxFlexLexer. You then -// include in your other sources once per lexer class: -// -// #undef yyFlexLexer -// #define yyFlexLexer xxFlexLexer -// #include -// -// #undef yyFlexLexer -// #define yyFlexLexer zzFlexLexer -// #include -// ... - -#ifndef __FLEX_LEXER_H -// Never included before - need to define base class. -#define __FLEX_LEXER_H - -#include -# ifndef FLEX_STD -# define FLEX_STD std:: -# endif - -extern "C++" { - -struct yy_buffer_state; -typedef int yy_state_type; - -class FlexLexer { -public: - virtual ~FlexLexer() { } - - const char* YYText() const { return yytext; } - int YYLeng() const { return yyleng; } - - virtual void - yy_switch_to_buffer( struct yy_buffer_state* new_buffer ) = 0; - virtual struct yy_buffer_state* - yy_create_buffer( FLEX_STD istream* s, int size ) = 0; - virtual void yy_delete_buffer( struct yy_buffer_state* b ) = 0; - virtual void yyrestart( FLEX_STD istream* s ) = 0; - - virtual int yylex() = 0; - - // Call yylex with new input/output sources. - int yylex( FLEX_STD istream* new_in, FLEX_STD ostream* new_out = 0 ) - { - switch_streams( new_in, new_out ); - return yylex(); - } - - // Switch to new input/output streams. A nil stream pointer - // indicates "keep the current one". - virtual void switch_streams( FLEX_STD istream* new_in = 0, - FLEX_STD ostream* new_out = 0 ) = 0; - - int lineno() const { return yylineno; } - - int debug() const { return yy_flex_debug; } - void set_debug( int flag ) { yy_flex_debug = flag; } - -protected: - char* yytext; - int yyleng; - int yylineno; // only maintained if you use %option yylineno - int yy_flex_debug; // only has effect with -d or "%option debug" -}; - -} -#endif - -#if defined(yyFlexLexer) || ! defined(yyFlexLexerOnce) -// Either this is the first time through (yyFlexLexerOnce not defined), -// or this is a repeated include to define a different flavor of -// yyFlexLexer, as discussed in the flex man page. -#define yyFlexLexerOnce - -extern "C++" { - -class yyFlexLexer : public FlexLexer { -public: - // arg_yyin and arg_yyout default to the cin and cout, but we - // only make that assignment when initializing in yylex(). - yyFlexLexer( FLEX_STD istream* arg_yyin = 0, FLEX_STD ostream* arg_yyout = 0 ); - - virtual ~yyFlexLexer(); - - void yy_switch_to_buffer( struct yy_buffer_state* new_buffer ); - struct yy_buffer_state* yy_create_buffer( FLEX_STD istream* s, int size ); - void yy_delete_buffer( struct yy_buffer_state* b ); - void yyrestart( FLEX_STD istream* s ); - - void yypush_buffer_state( struct yy_buffer_state* new_buffer ); - void yypop_buffer_state(void); - -#ifndef yywrap -int yywrap(); -#endif - virtual int yylex(); - virtual void switch_streams( FLEX_STD istream* new_in, FLEX_STD ostream* new_out ); - -protected: - virtual int LexerInput( char* buf, int max_size ); - virtual void LexerOutput( const char* buf, int size ); - virtual void LexerError( const char* msg ); - - void yyunput( int c, char* buf_ptr ); - int yyinput(); - - void yy_load_buffer_state(); - void yy_init_buffer( struct yy_buffer_state* b, FLEX_STD istream* s ); - void yy_flush_buffer( struct yy_buffer_state* b ); - - int yy_start_stack_ptr; - int yy_start_stack_depth; - int* yy_start_stack; - - void yy_push_state( int new_state ); - void yy_pop_state(); - int yy_top_state(); - - yy_state_type yy_get_previous_state(); - yy_state_type yy_try_NUL_trans( yy_state_type current_state ); - int yy_get_next_buffer(); - - FLEX_STD istream* yyin; // input source for default LexerInput - FLEX_STD ostream* yyout; // output sink for default LexerOutput - - // yy_hold_char holds the character lost when yytext is formed. - char yy_hold_char; - - // Number of characters read into yy_ch_buf. - int yy_n_chars; - - // Points to current character in buffer. - char* yy_c_buf_p; - - int yy_init; // whether we need to initialize - int yy_start; // start state number - - // Flag which is used to allow yywrap()'s to do buffer switches - // instead of setting up a fresh yyin. A bit of a hack ... - int yy_did_buffer_switch_on_eof; - - - size_t yy_buffer_stack_top; /**< index of top of stack. */ - size_t yy_buffer_stack_max; /**< capacity of stack. */ - struct yy_buffer_state ** yy_buffer_stack; /**< Stack as an array. */ - void yyensure_buffer_stack(void); - - // The following are not always needed, but may be depending - // on use of certain flex features (like REJECT or yymore()). - - yy_state_type yy_last_accepting_state; - char* yy_last_accepting_cpos; - - yy_state_type* yy_state_buf; - yy_state_type* yy_state_ptr; - - char* yy_full_match; - int* yy_full_state; - int yy_full_lp; - - int yy_lp; - int yy_looking_for_trail_begin; - - int yy_more_flag; - int yy_more_len; - int yy_more_offset; - int yy_prev_more_offset; -}; - -} - -#endif diff --git a/parser/dumptree.cpp b/parser/dumptree.cpp index 2a21816..84d1ffa 100644 --- a/parser/dumptree.cpp +++ b/parser/dumptree.cpp @@ -1,203 +1,202 @@ /* This file is part of KDevelop Copyright 2002-2005 Roberto Raggi Copyright 2006-2008 Hamish Rodda 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. */ #include "dumptree.h" //#include "lexer.h" #include "parsesession.h" #include "javaast.h" #include "kdev-pg-token-stream.h" #include - -#include +#include static char const * const names[] = { "additive_expression", "additive_expression_rest", "annotation", "annotation_arguments", "annotation_element_array_initializer", "annotation_element_array_value", "annotation_element_value", "annotation_element_value_pair", "annotation_method_declaration", "annotation_type_body", "annotation_type_declaration", "annotation_type_field", "array_access", "array_creator_rest", "array_type_dot_class", "assert_statement", "bit_and_expression", "bit_or_expression", "bit_xor_expression", "block", "block_statement", "break_statement", "builtin_type", "builtin_type_dot_class", "cast_expression", "catch_clause", "class_access_data", "class_body", "class_declaration", "class_extends_clause", "class_field", "class_or_interface_type_name", "class_or_interface_type_name_part", "class_type", "compilation_unit", "conditional_expression", "constructor_declaration", "continue_statement", "do_while_statement", "embedded_statement", "enum_body", "enum_constant", "enum_constant_body", "enum_constant_field", "enum_declaration", "equality_expression", "equality_expression_rest", "expression", "for_clause_traditional_rest", "for_control", "for_statement", "foreach_declaration_data", "identifier", "if_statement", "implements_clause", "import_declaration", "interface_body", "interface_declaration", "interface_extends_clause", "interface_field", "interface_method_declaration", "labeled_statement", "literal", "logical_and_expression", "logical_or_expression", "mandatory_array_builtin_type", "mandatory_declarator_brackets", "method_call_data", "method_declaration", "multiplicative_expression", "multiplicative_expression_rest", "new_expression", "non_array_type", "non_wildcard_type_arguments", "optional_argument_list", "optional_array_builtin_type", "optional_declarator_brackets", "optional_modifiers", "optional_parameter_declaration_list", "optional_parameter_modifiers", "package_declaration", "parameter_declaration", "parameter_declaration_ellipsis", "postfix_operator", "primary_atom", "primary_expression", "primary_selector", "qualified_identifier", "qualified_identifier_with_optional_star", "relational_expression", "relational_expression_rest", "return_statement", "shift_expression", "shift_expression_rest", "simple_name_access_data", "statement_expression", "super_access_data", "super_suffix", "switch_label", "switch_section", "switch_statement", "synchronized_statement", "this_access_data", "this_call_data", "throw_statement", "throws_clause", "try_statement", "type", "type_argument", "type_argument_type", "type_arguments", "type_arguments_or_parameters_end", "type_declaration", "type_parameter", "type_parameters", "unary_expression", "unary_expression_not_plusminus", "variable_array_initializer", "variable_declaration", "variable_declaration_data", "variable_declaration_rest", "variable_declaration_split_data", "variable_declaration_statement", "variable_declarator", "variable_initializer", "while_statement", "wildcard_type", "wildcard_type_bounds" }; using namespace java; DumpTree::DumpTree() : m_parseSession(0), indent(0) { } void DumpTree::dump( AstNode * node, ParseSession* parseSession ) { m_parseSession = parseSession; visitNode(node); m_parseSession = 0; } void DumpTree::visitNode(AstNode *node) { QString nodeText; if( m_parseSession && node ) { for( qint64 a = node->startToken; a <= node->endToken; a++ ) { if( !nodeText.isEmpty() ) nodeText += ' '; nodeText += m_parseSession->symbol(a); } } if (node) { - kDebug() << QString(indent * 2, ' ').toLatin1().constData() << names[node->kind - 1000] + qDebug() << QString(indent * 2, ' ').toLatin1().constData() << names[node->kind - 1000] << "[" << node->startToken << "," << node->endToken << "]" << nodeText << endl; } ++indent; DefaultVisitor::visitNode(node); --indent; if (node) { - kDebug() << QString(indent * 2, ' ').toLatin1().constData() << names[node->kind - 1000]; + qDebug() << QString(indent * 2, ' ').toLatin1().constData() << names[node->kind - 1000]; } } DumpTree::~ DumpTree( ) { } diff --git a/parser/java.g b/parser/java.g index 32e00bd..59e3fa5 100644 --- a/parser/java.g +++ b/parser/java.g @@ -1,1879 +1,1879 @@ -- This file is part of KDevelop. -- Copyright (c) 2005, 2006 Jakob Petsovits -- -- This grammar 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 grammar 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 -- Lesser 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. ----------------------------------------------------------------- -- Grammar for Java 1.3, 1.4 or 1.5 -- Modelled after the public domain ANTLR Java 1.5 grammar at -- http://www.antlr.org/grammar/1090713067533/index.html -- (Version 1.22.5 from January 03, 2005) -- and the reference grammar of the Java language specification, -- Third Edition, at http://java.sun.com/docs/books/jls/. ----------------------------------------------------------------- -- 7 first/follow conflicts: -- - The AT conflict in compilationUnit -- (namely: packageDeclaration vs. typeDeclaration). -- (manually solved, 2 conflicts - which is actually only one) -- - The DOT conflict in classOrInterfaceTypeName: -- Caused by the may-end-with-epsilon typeArguments. It doesn't apply -- at all, only kdevelop-pg thinks it does. Code segments... -- (done right by default, 1 conflict) -- - The LBRACKET conflict in optionalDeclaratorBrackets: -- No idea where it stems from, but I think it should be ok. -- (done right by default, 1 conflict) -- - The COMMA conflict in typeArguments: -- the approach for catching ">" signs works this way, and the conflict -- is resolved by the trailing condition at the end of the rule. -- (manually resolved, 1 conflict) -- - The LBRACKET conflict in arrayCreatorRest. -- (manually resolved, 1 conflict) -- - The AT conflict in optionalModifiers. -- (manually resolved, 1 conflict) -- 12 first/first conflicts: -- - The IDENTIFIER conflict in annotationArguments -- (manually resolved, 1 conflict) -- - The IDENTIFIER conflicts in *_field, -- between the method name and variable name -- (manually resolved, 4 conflicts) -- - The IDENTIFIER conflict in classField -- (manually resolved, 1 conflict) -- - The STATIC conflict in classField -- (manually resolved, 1 conflict) -- - The SYNCHRONIZED conflict in blockStatement. -- (manually resolved, 1 conflict) -- - The IDENTIFIER conflict (labels) in embeddedStatement -- (manually resolved, 1 conflict) -- - The IDENTIFIER conflicts in primarySelector and superSuffix. -- Could be written without conflict, but done on purpose to tell methods -- (with possible type arguments) and variables (without those) apart. -- (manually resolved, 2 identical conflicts) -- - The LBRACKET conflict in arrayCreatorRest. -- This is by design and works as expected. -- (manually resolved, 1 conflict) -- Total amount of conflicts: 19 ------------------------------------------------------------ -- Global declarations ------------------------------------------------------------ [: namespace KDevelop { class DUContext; } :] %parser_declaration_header "QtCore/QString" %parser_declaration_header "QtCore/QDebug" %parser_declaration_header "kdev-pg-list.h" %export_macro "KDEVJAVAPARSER_EXPORT" -%export_macro_header "javaparserexport.h" +%export_macro_header "javaparser_export.h" ------------------------------------------------------------ -- Enumeration types for additional AST members, -- in the global "java" namespace ------------------------------------------------------------ %namespace [: enum WildcardTypeBoundsEnum { WildcardTypeExtends, WildcardTypeSuper }; enum BuiltInTypeEnum { BuiltInTypeVoid, BuiltInTypeBoolean, BuiltInTypeByte, BuiltInTypeChar, BuiltInTypeShort, BuiltInTypeInt, BuiltInTypeFloat, BuiltInTypeLong, BuiltInTypeDouble }; enum BranchTypeEnum { BranchCase, BranchDefault }; enum AssignmentOperatorEnum { AssignmentOperatorNone, AssignmentOperatorPlain, AssignmentOperatorPlus, AssignmentOperatorMinus, AssignmentOperatorStar, AssignmentOperatorSlash, AssignmentOperatorBitAnd, AssignmentOperatorBitOr, AssignmentOperatorBitXOr, AssignmentOperatorRemainder, AssignmentOperatorLShift, AssignmentOperatorRShiftSigned, AssignmentOperatorRShiftUnsigned }; enum EqualityOperatorEnum { EqualityOperatorEqual, EqualityOperatorNotEqual }; enum RelationalOperatorEnum { RelationalOperatorLessThan, RelationalOperatorGreaterThan, RelationalOperatorLessEqual, RelationalOperatorGreaterEqual }; enum ShiftOperatorEnum { ShiftOperatorLShift, ShiftOperatorRShiftSigned, ShiftOperatorRShiftUnsigned }; enum AdditiveOperatorEnum { AdditiveOperatorPlus, AdditiveOperatorMinus }; enum MultiplicativeOperatorEnum { MultiplicativeOperatorStar, MultiplicativeOperatorSlash, MultiplicativeOperatorRemainder }; enum UnaryExpressionPlusMinusEnum { UnaryExpressionIncrement, UnaryExpressionDecrement, UnaryExpressionMinus, UnaryExpressionPlus, UnaryExpressionNotPlusMinus }; enum UnaryExpressionNotPlusMinusEnum { UnaryExpressionBitwiseNot, UnaryExpressionLogicalNot, UnaryExpressionCast, UnaryExpressionPrimary }; enum PostfixOperatorEnum { PostfixOperatorIncrement, PostfixOperatorDecrement }; enum ModifierFlags { ModifierPrivate = 1, ModifierPublic = 1 << 1, ModifierProtected = 1 << 2, ModifierStatic = 1 << 3, ModifierTransient = 1 << 4, ModifierFinal = 1 << 5, ModifierAbstract = 1 << 6, ModifierNative = 1 << 7, ModifierSynchronized = 1 << 8, ModifierVolatile = 1 << 9, ModifierStrictFP = 1 << 10 }; enum LiteralTypeEnum { LiteralTrue, LiteralFalse, LiteralNull, LiteralInteger, LiteralFloatingPoint, LiteralCharacter, LiteralString }; :] ------------------------------------------------------------ -- Ast Node class members ------------------------------------------------------------ %ast_extra_members [: KDevelop::DUContext* ducontext; :] ------------------------------------------------------------ -- Parser class members ------------------------------------------------------------ %parserclass (public declaration) [: /** * Transform the raw input into tokens. * When this method returns, the parser's token stream has been filled * and any parse_*() method can be called. */ void tokenize( char *contents ); /** * The compatibilityMode() status variable tells which version of Java * should be checked against. */ enum JavaCompatibilityMode { Java13Compatibility = 130, Java14Compatibility = 140, Java15Compatibility = 150 }; Parser::JavaCompatibilityMode compatibilityMode(); void setCompatibilityMode( Parser::JavaCompatibilityMode mode ); enum ProblemType { Error, Warning, Info }; void reportProblem( Parser::ProblemType type, const QString& message ); :] %parserclass (private declaration) [: Parser::JavaCompatibilityMode m_compatibilityMode; struct ParserState { // ltCounter stores the amount of currently open type arguments rules, // all of which are beginning with a less than ("<") character. // This way, also SIGNED_RSHIFT (">>") and UNSIGNED_RSHIFT (">>>") can be used // to close type arguments rules, in addition to GREATER_THAN (">"). int ltCounter; }; ParserState m_state; :] %parserclass (constructor) [: m_compatibilityMode = Java15Compatibility; :] ------------------------------------------------------------ -- List of defined tokens ------------------------------------------------------------ -- keywords: %token ABSTRACT ("abstract"), ASSERT ("assert"), BOOLEAN ("boolean"), BREAK ("break"), BYTE ("byte"), CASE ("case"), CATCH ("catch"), CHAR ("char"), CLASS ("class"), CONST ("const"), CONTINUE ("continue"), DEFAULT ("default"), DO ("do"), DOUBLE ("double"), ELSE ("else"), ENUM ("enum"), EXTENDS ("extends"), FINAL ("final"), FINALLY ("finally"), FLOAT ("float"), FOR ("for"), GOTO ("goto"), IF ("if"), IMPLEMENTS ("implements"), IMPORT ("import"), INSTANCEOF ("instanceof"), INT ("int"), INTERFACE ("interface"), LONG ("long"), NATIVE ("native"), NEW ("new"), PACKAGE ("package"), PRIVATE ("private"), PROTECTED ("protected"), PUBLIC ("public"), RETURN ("return"), SHORT ("short"), STATIC ("static"), STRICTFP ("strictfp"), SUPER ("super"), SWITCH ("switch"), SYNCHRONIZED ("synchronized"), THIS ("this"), THROW ("throw"), THROWS ("throws"), TRANSIENT ("transient"), TRY ("try"), VOID ("void"), VOLATILE ("volatile"), WHILE ("while") ;; -- seperators: %token LPAREN ("("), RPAREN (")"), LBRACE ("{"), RBRACE ("}"), LBRACKET ("["), RBRACKET ("]"), SEMICOLON (";"), COMMA (","), DOT ("."), AT ("@") ;; -- operators: %token ASSIGN ("="), LESS_THAN ("<"), GREATER_THAN (">"), BANG ("!"), TILDE ("~"), QUESTION ("?"), COLON (":"), EQUAL ("=="), LESS_EQUAL ("<="), GREATER_EQUAL (">="), NOT_EQUAL ("!="), LOG_AND ("&&"), LOG_OR ("||"), INCREMENT ("++"), DECREMENT ("--"), PLUS ("+"), MINUS ("-"), STAR ("*"), SLASH ("/"), BIT_AND ("&"), BIT_OR ("|"), BIT_XOR ("^"), REMAINDER ("%"), LSHIFT ("<<"), SIGNED_RSHIFT (">>"), UNSIGNED_RSHIFT (">>>"), PLUS_ASSIGN ("+="), MINUS_ASSIGN ("-="), STAR_ASSIGN ("*="), SLASH_ASSIGN ("/="), BIT_AND_ASSIGN ("&="), BIT_OR_ASSIGN ("|="), BIT_XOR_ASSIGN ("^="), REMAINDER_ASSIGN ("%="), LSHIFT_ASSIGN ("<<="), SIGNED_RSHIFT_ASSIGN (">>="), UNSIGNED_RSHIFT_ASSIGN (">>>="), ELLIPSIS ("...") ;; -- literals and identifiers: %token TRUE ("true"), FALSE ("false"), NULL ("null"), INTEGER_LITERAL ("integer literal"), FLOATING_POINT_LITERAL ("floating point literal"), CHARACTER_LITERAL ("character literal"), STRING_LITERAL ("string literal"), IDENTIFIER ("identifier") ;; -- token that makes the parser fail in any case: %token INVALID ("invalid token") ;; ------------------------------------------------------------ -- Start of the actual grammar ------------------------------------------------------------ 0 [: m_state.ltCounter = 0; :] -- There is a conflict between packageDeclaration and typeDeclaration -- (both can start with annotations) which requires arbitrary-length LL(k). -- The following construct uses backtracking with try/rollback to work -- around this issue. try/rollback(packageDeclaration=packageDeclaration) catch(0) try/recover(#importDeclaration=importDeclaration)* try/recover(#typeDeclaration=typeDeclaration)* -> compilationUnit ;; -- A PACKAGE DECLARATION: optional annotations followed by "package", -- then the package identifier. -- 1 first/first conflict, because annotation as well as "| 0" -- inside of compilationUnit may both be 0. The ANTLR grammar -- checks on ?[:annotations "package":] to do a packageDeclaration. try/recover(#annotation=annotation)* PACKAGE packageName=qualifiedIdentifier SEMICOLON -> packageDeclaration ;; -- An IMPORT DECLARATION is "import" followed by a package or type (=class) name. IMPORT ( STATIC [: (*yynode)->staticImport = true; :] | 0 [: (*yynode)->staticImport = false; :] ) identifierName=qualifiedIdentifierWithOptionalStar SEMICOLON -> importDeclaration [ member variable staticImport: bool; ] ;; -- A TYPE DECLARATION is either a class, interface, enum or annotation. ( modifiers:optionalModifiers ( classDeclaration=classDeclaration[modifiers] | enumDeclaration=enumDeclaration[modifiers] | interfaceDeclaration=interfaceDeclaration[modifiers] | annotationTypeDeclaration=annotationTypeDeclaration[modifiers] ) | SEMICOLON ) -> typeDeclaration ;; -- ANNOTATIONS look for example like @Info( name="Jakob", born=1983 ), -- or @Info("Jakob"), or just @Info, and are attached to a method, -- class, or package. @Info is equivalent to @Info(). AT typeName=qualifiedIdentifier ( LPAREN (args=annotationArguments | 0) RPAREN [: (*yynode)->hasParentheses = true; :] | 0 [: (*yynode)->hasParentheses = false; :] ) -> annotation [ member variable hasParentheses: bool; ] ;; ( ( ?[: LA(2).kind == Token_ASSIGN :] #valuePair=annotationElementValuePair @ COMMA ) | elementValue=annotationElementValue -- elementName is "value" here ) -> annotationArguments ;; elementName=identifier ASSIGN elementValue=annotationElementValue -> annotationElementValuePair ;; conditionalExpression=conditionalExpression | annotation=annotation | elementArrayInitializer=annotationElementArrayInitializer -> annotationElementValue ;; -- Same as annotationElementValue, but elementArrayInitializer is excluded. -- That's because nested annotation array initialisers are not valid. -- (The Java specification hides that in a short "discussion" area.) conditionalExpression=conditionalExpression | annotation=annotation -> annotationElementArrayValue ;; LBRACE ( #elementValue=annotationElementArrayValue ( COMMA [: if (yytoken == Token_RBRACE) { break; } :] #elementValue=annotationElementArrayValue )* | 0 ) RBRACE -> annotationElementArrayInitializer ;; -- Definition of a Java CLASS CLASS className=identifier ( ?[: compatibilityMode() >= Java15Compatibility :] typeParameters=typeParameters | 0 ) -- in Java 1.5 or higher, it might have type parameters (extends=classExtendsClause | 0) -- it might have a super class (implements=implementsClause | 0) -- it might implement some interfaces body=classBody -> classDeclaration [ argument member node modifiers: optionalModifiers; ] ;; -- Definition of a Java INTERFACE INTERFACE interfaceName=identifier ( ?[: compatibilityMode() >= Java15Compatibility :] typeParameters=typeParameters | 0 ) -- in Java 1.5 or higher, it might have type parameters (extends=interfaceExtendsClause | 0) -- it might extend other interfaces body=interfaceBody -> interfaceDeclaration [ argument member node modifiers: optionalModifiers; ] ;; -- Definition of ENUMERATIONs and ANNOTATION TYPEs ENUM enumName=identifier (implements=implementsClause | 0) -- it might implement some interfaces body=enumBody -> enumDeclaration [ argument member node modifiers: optionalModifiers; ] ;; AT INTERFACE annotationTypeName=identifier body=annotationTypeBody -> annotationTypeDeclaration [ argument member node modifiers: optionalModifiers; ] ;; -- BODIES of classes, interfaces, annotation types and enums. LBRACE try/recover(#declaration=classField)* RBRACE -> classBody ;; LBRACE try/recover(#declaration=interfaceField)* RBRACE -> interfaceBody ;; LBRACE try/recover(#annotationTypeField=annotationTypeField)* RBRACE -> annotationTypeBody ;; -- In an enum body, you can have zero or more enum constants -- followed by any number of fields like a regular class. LBRACE ( try/recover(#enumConstant=enumConstant) ( COMMA [: if ( yytoken == Token_RBRACE || yytoken == Token_SEMICOLON ) { break; } :] -- if the list is over, then exit the loop try/recover(#enumConstant=enumConstant) )* | 0 ) ( SEMICOLON try/recover(#classField=classField)* | 0 ) RBRACE -> enumBody ;; -- An enum constant may have optional parameters and may have a class body try/recover(#annotation=annotation)* identifier=identifier ( LPAREN arguments=optionalArgumentList RPAREN | 0 ) ( body=enumConstantBody | 0 ) -> enumConstant ;; LBRACE try/recover(#declaration=enumConstantField)* RBRACE -> enumConstantBody ;; -- Short CLAUSES used in various declarations EXTENDS type=classOrInterfaceTypeName -> classExtendsClause ;; EXTENDS #type=classOrInterfaceTypeName @ COMMA -> interfaceExtendsClause ;; IMPLEMENTS #type=classOrInterfaceTypeName @ COMMA -> implementsClause ;; THROWS #identifier=qualifiedIdentifier @ COMMA -> throwsClause ;; -- Now on to what happens inside the class, interface, etc. bodies: -- An ANNOTATION TYPE FIELD. The Java specification has a bug here, -- two different AnnotationTypeElementDeclarations in the book's body -- and the grammar appendix. I chose the one from the body, -- which is the same that the ANTLR grammar also uses. ( modifiers:optionalModifiers ( classDeclaration=classDeclaration[modifiers] | enumDeclaration=enumDeclaration[modifiers] | interfaceDeclaration=interfaceDeclaration[modifiers] | annotationTypeDeclaration=annotationTypeDeclaration[modifiers] | type:type ( -- annotation method without arguments: ?[: LA(2).kind == Token_LPAREN :] -- resolves the identifier conflict -- between method name and variable name methodDeclaration=annotationMethodDeclaration[ modifiers, type ] | -- or a ConstantDeclaration: #variableDeclarator:variableDeclarator @ COMMA SEMICOLON constantDeclaration=variableDeclarationData[ modifiers, type, variableDeclaratorSequence ] ) ) | SEMICOLON ) -> annotationTypeField ;; -- A CLASS FIELD, representing the various things -- that can be defined inside a class. ( ?[: !(yytoken == Token_STATIC && LA(2).kind == Token_LBRACE) :] -- resolves the 'static' conflict, see further down modifiers:optionalModifiers ( classDeclaration=classDeclaration[modifiers] | enumDeclaration=enumDeclaration[modifiers] | interfaceDeclaration=interfaceDeclaration[modifiers] | annotationTypeDeclaration=annotationTypeDeclaration[modifiers] | -- A generic method/ctor has the typeParameters before the return type. -- This is not allowed for variable definitions, which is checked later. ( ?[: compatibilityMode() >= Java15Compatibility :] typeParameters:typeParameters | 0 ) ( -- constructor declaration (without prepended type specification) ?[: LA(2).kind == Token_LPAREN :] -- resolves the identifier conflict with type constructorDeclaration=constructorDeclaration[ modifiers, typeParameters ] | -- method or variable declaration type:type ( ?[: LA(2).kind == Token_LPAREN :] -- resolves the identifier -- conflict between method name and variable name methodDeclaration=methodDeclaration[ modifiers, typeParameters, type ] | ?[: typeParameters == 0 :] #variableDeclarator:variableDeclarator @ COMMA SEMICOLON variableDeclaration=variableDeclarationData[ modifiers, type, variableDeclaratorSequence ] | 0 [: reportProblem( Error, "Expected method declaration after type parameter list" ); :] SEMICOLON -- not really needed, but avoids conflict warnings ) ) ) | instanceInitializerBlock=block -- "{...}" instance initializer | -- The static class initializer block ("static {...}") has a conflict with -- the modifiers from above, which can also be static. A block must always -- start with "{", so when encountering static, this can be used to resolve -- this conflict. (Lookahead done at the top of the rule.) STATIC staticInitializerBlock=block | SEMICOLON ) -> classField ;; -- An ENUM CONSTANT FIELD is just like a class field but without -- the possibility of a constructor definition or a static initializer. ( modifiers:optionalModifiers ( classDeclaration=classDeclaration[modifiers] | enumDeclaration=enumDeclaration[modifiers] | interfaceDeclaration=interfaceDeclaration[modifiers] | annotationTypeDeclaration=annotationTypeDeclaration[modifiers] | -- A generic method has the typeParameters before the return type. -- This is not allowed for variable definitions, which is checked later. ( ?[: compatibilityMode() >= Java15Compatibility :] typeParameters:typeParameters | 0 ) type:type ( ?[: LA(2).kind == Token_LPAREN :] -- resolves the identifier conflict -- between method name and variable name methodDeclaration=methodDeclaration[ modifiers, typeParameters, type ] | ?[: typeParameters == 0 :] #variableDeclarator:variableDeclarator @ COMMA SEMICOLON variableDeclaration=variableDeclarationData[ modifiers, type, variableDeclaratorSequence ] | 0 [: reportProblem( Error, "Expected method declaration after type parameter list" ); :] SEMICOLON -- not really needed, but avoids conflict warnings ) ) | instanceInitializerBlock=block -- "{...}" instance initializer | SEMICOLON ) -> enumConstantField ;; -- An INTERFACE FIELD is the same as an enum constant field but without -- the possibility of any initializers or method blocks. ( modifiers:optionalModifiers ( classDeclaration=classDeclaration[modifiers] | enumDeclaration=enumDeclaration[modifiers] | interfaceDeclaration=interfaceDeclaration[modifiers] | annotationTypeDeclaration=annotationTypeDeclaration[modifiers] | -- A generic method has the typeParameters before the return type. -- This is not allowed for variable definitions, which is checked later. 0 [: bool hasTypeParameters = false; :] ( ?[: compatibilityMode() >= Java15Compatibility :] typeParameters:typeParameters [: hasTypeParameters = true; :] | 0 ) type:type ( ?[: LA(2).kind == Token_LPAREN :] -- resolves the identifier conflict -- between method name and variable name interfaceMethodDeclaration=interfaceMethodDeclaration[ modifiers, typeParameters, type ] | ?[: typeParameters == 0 :] #variableDeclarator:variableDeclarator @ COMMA SEMICOLON variableDeclaration=variableDeclarationData[ modifiers, type, variableDeclaratorSequence ] | 0 [: reportProblem( Error, "Expected method declaration after type parameter list" ); :] SEMICOLON -- not really needed, but avoids conflict warnings ) ) | SEMICOLON ) -> interfaceField ;; annotationName=identifier LPAREN RPAREN -- declaratorBrackets=optionalDeclaratorBrackets -- ANTLR grammar's bug: -- It's not in the Java Spec, and obviously has been copied -- from classField even if it doesn't belong here. (DEFAULT annotationElementValue=annotationElementValue | 0) SEMICOLON -> annotationMethodDeclaration [ argument member node modifiers: optionalModifiers; argument member node returnType: type; ] ;; className=identifier LPAREN parameters=optionalParameterDeclarationList RPAREN (throwsClause=throwsClause | 0) body=block -- leaving out explicit this(...) and super(...) invocations, -- these are just normal statements for this grammar -> constructorDeclaration [ argument member node modifiers: optionalModifiers; argument member node typeParameters: typeParameters; ] ;; methodName=identifier LPAREN parameters=optionalParameterDeclarationList RPAREN declaratorBrackets=optionalDeclaratorBrackets (throwsClause=throwsClause | 0) (body=block | SEMICOLON) -- semicolons are used for abstract methods -> methodDeclaration [ argument member node modifiers: optionalModifiers; argument member node typeParameters: typeParameters; argument member node returnType: type; ] ;; methodName=identifier LPAREN parameters=optionalParameterDeclarationList RPAREN declaratorBrackets=optionalDeclaratorBrackets (throwsClause=throwsClause | 0) SEMICOLON -> interfaceMethodDeclaration [ argument member node modifiers: optionalModifiers; argument member node typeParameters: typeParameters; argument member node returnType: type; ] ;; -- So much for the rough structure, now we get into the details -- A PARAMETER DECLARATION LIST is part of a method header and can contain -- zero or more parameters, optionally ending with a variable-length parameter. -- It's not as hackish as it used to be, nevertheless it could still be nicer. 0 [: bool ellipsisOccurred = false; :] ( #parameterDeclaration=parameterDeclarationEllipsis[&ellipsisOccurred] @ ( 0 [: if( ellipsisOccurred == true ) { break; } :] -- Don't proceed after the ellipsis. If you find a cleaner way -- to exit the loop when ellipsisOccurred == true, -- please use that one instead of this construct (see below). COMMA ) | 0 ) -> optionalParameterDeclarationList ;; -- How it _should_ look: -- -- 0 [: bool ellipsisOccurred = false; :] -- ( -- #parameterDeclaration=parameterDeclarationEllipsis[&ellipsisOccurred] -- @ ( ?[: ellipsisOccurred == false :] COMMA ) -- -- kdev-pg dismisses this condition! -- | -- 0 -- ) -- -> optionalParameterDeclarationList ;; parameterModifiers=optionalParameterModifiers type=type ( ELLIPSIS [: (*yynode)->hasEllipsis = true; *ellipsisOccurred = true; :] | 0 [: (*yynode)->hasEllipsis = false; :] ) variableName=identifier declaratorBrackets=optionalDeclaratorBrackets -> parameterDeclarationEllipsis [ member variable hasEllipsis: bool; argument temporary variable ellipsisOccurred: bool*; ] ;; 0 [: (*yynode)->hasModifierFinal = false; :] ( FINAL [: (*yynode)->hasModifierFinal = true; :] | try/recover(#modifierAnnotation=annotation) )* -> optionalParameterModifiers [ member variable hasModifierFinal: bool; ] ;; -- An OPTIONAL ARGUMENT LIST is used when calling methods -- (not for declaring them, that's what parameter declaration lists are for). try/recover(#expression=expression @ COMMA) | 0 -> optionalArgumentList ;; -- The body of a CONSTRUCTOR METHOD is the same as a normal block, except that -- it's possible to have a constructor call like this(...) or super(...) -- at the beginning of the block. This causes a conflict which is difficult -- to resolve, so classField uses block instead of constructorBody. -- -- LBRACE -- ( try/recover(explicitConstructorInvocation=explicitConstructorInvocation) -- | 0 -- ) -- try/recover(#statement=embeddedStatement)* -- RBRACE -- -> constructorBody ;; -- -- -- Catches obvious constructor calls, but not the expr.super(...) calls: -- -- ( ?[: compatibilityMode() >= Java15Compatibility :] -- typeArguments=typeArguments -- | 0 -- ) -- (invocatedConstructor=THIS | invocatedConstructor=SUPER) -- LPAREN arguments=argumentList RPAREN SEMICOLON -- -> explicitConstructorInvocation ;; -- Type parameters and type arguments, the two rules responsible for the -- greater-than special casing. (This is the generic aspect in Java >= 1.5.) -- TYPE PARAMETERS are used in class, interface etc. declarations to -- determine the generic types allowed as type argument. LESS_THAN [: int currentLtLevel = m_state.ltCounter; m_state.ltCounter++; :] #typeParameter=typeParameter @ COMMA ( typeArgumentsOrParametersEnd | 0 -- they can also be changed by typeParameter or typeArgument ) -- make sure we have gobbled up enough '>' characters -- if we are at the "top level" of nested typeParameters productions [: if (currentLtLevel == 0 && m_state.ltCounter != currentLtLevel ) { if (!mBlockErrors) { reportProblem(Error, "The amount of closing ``>'' characters is incorrect"); } return false; } :] -> typeParameters ;; identifier=identifier (EXTENDS (#extendsType=classOrInterfaceTypeName @ BIT_AND) | 0) -> typeParameter ;; -- TYPE ARGUMENTS are used in initializers, invocations, etc. to -- specify the exact types for this generic class/method instance. LESS_THAN [: int currentLtLevel = m_state.ltCounter; m_state.ltCounter++; :] #typeArgument=typeArgument ( -- only proceed when we are at the right nesting level: 0 [: if( m_state.ltCounter != currentLtLevel + 1 ) { break; } :] COMMA #typeArgument=typeArgument )* ( typeArgumentsOrParametersEnd | 0 -- they can also be changed by typeParameter or typeArgument ) -- make sure we have gobbled up enough '>' characters -- if we are at the "top level" of nested typeArguments productions [: if (currentLtLevel == 0 && m_state.ltCounter != currentLtLevel ) { if (!mBlockErrors) { reportProblem(Error, "The amount of closing ``>'' characters is incorrect"); } return false; } :] -> typeArguments ;; LESS_THAN [: int currentLtLevel = m_state.ltCounter; m_state.ltCounter++; :] #typeArgumentType=typeArgumentType ( -- only proceed when we are at the right nesting level: 0 [: if( m_state.ltCounter != currentLtLevel + 1 ) { break; } :] COMMA #typeArgumentType=typeArgumentType )* ( typeArgumentsOrParametersEnd | 0 -- they can also be changed by typeParameter or typeArgument ) -- make sure we have gobbled up enough '>' characters -- if we are at the "top level" of nested typeArguments productions [: if (currentLtLevel == 0 && m_state.ltCounter != currentLtLevel ) { if (!mBlockErrors) { reportProblem(Error, "The amount of closing ``>'' characters is incorrect"); } return false; } :] -> nonWildcardTypeArguments ;; typeArgumentType=typeArgumentType | wildcardType=wildcardType -> typeArgument ;; -- Any type specification except primitive types is allowed as type argument. -- Arrays of primitive types are allowed nonetheless. classType=classType | mandatoryArrayBuiltInType=mandatoryArrayBuiltInType -> typeArgumentType ;; QUESTION (bounds=wildcardTypeBounds | 0) -> wildcardType ;; ( EXTENDS [: (*yynode)->extendsOrSuper = WildcardTypeExtends; :] | SUPER [: (*yynode)->extendsOrSuper = WildcardTypeSuper; :] ) type=classType -> wildcardTypeBounds [ member variable extendsOrSuper: WildcardTypeBoundsEnum; ] ;; GREATER_THAN [: m_state.ltCounter -= 1; :] -- ">" | SIGNED_RSHIFT [: m_state.ltCounter -= 2; :] -- ">>" | UNSIGNED_RSHIFT [: m_state.ltCounter -= 3; :] -- ">>>" -> typeArgumentsOrParametersEnd ;; -- And now for the good stuff: statements, expressions and the likes. Yay! -- This is a BLOCK, a list of statements. It is used in many contexts: -- - Inside a class definition prefixed with "static" as class initializer -- - Inside a class definition without "static" as instance initializer -- - As the body of a method -- - As a completely independent braced block of code inside a method, -- starting a new scope for variable definitions LBRACE try/recover(#statement=blockStatement)* RBRACE -> block ;; -- A BLOCK STATEMENT is either an embedded statement, a variable declaration -- or a type declaration (you know, nested classes and the likes...). -- Variable declarations, as well as expression statements, can start with -- class1.bla or similar. This is only solvable with LL(k), so we need -- backtracking in form of the try/rollback() construct. try/rollback(variableDeclarationStatement=variableDeclarationStatement) catch( -- resolves the SYNCHRONIZED conflict between -- synchronizedStatement and modifier: ?[: (yytoken != Token_SYNCHRONIZED) || (yytoken == Token_SYNCHRONIZED && LA(2).kind == Token_LPAREN) :] statement=embeddedStatement | -- Inside a block, our four "complex types" can be declared -- (enums, nested classes and the likes...): modifiers:optionalModifiers ( classDeclaration=classDeclaration[modifiers] | enumDeclaration=enumDeclaration[modifiers] | interfaceDeclaration=interfaceDeclaration[modifiers] | annotationTypeDeclaration=annotationTypeDeclaration[modifiers] ) ) -> blockStatement ;; -- VARIABLE DECLARATIONS, initializers, etc. -- TODO: the modifiers need to be checked (after parsing) if they contain -- only the allowed modifiers, which is FINAL and annotations. variableDeclaration=variableDeclaration SEMICOLON -> variableDeclarationStatement ;; modifiers:optionalModifiers type:type #variableDeclarator:variableDeclarator @ COMMA data=variableDeclarationData[ modifiers, type, variableDeclaratorSequence ] -> variableDeclaration ;; 0 -> variableDeclarationData [ argument member node modifiers: optionalModifiers; argument member node type: type; argument member node #declarator: variableDeclarator; ] ;; ( ASSIGN firstInitializer=variableInitializer | 0 ) ( COMMA #variableDeclarator=variableDeclarator )* -> variableDeclarationRest ;; -- A VARIABLE DECLARATOR, as used in a variableDeclaration or *Field variableName=identifier declaratorBrackets=optionalDeclaratorBrackets ( ASSIGN initializer=variableInitializer | 0 ) -> variableDeclarator ;; ( expression=expression | arrayInitializer=variableArrayInitializer ) -> variableInitializer ;; LBRACE ( ( #variableInitializer=variableInitializer ( COMMA [: if (yytoken == Token_RBRACE) { break; } :] #variableInitializer=variableInitializer )* ) | 0 ) RBRACE -> variableArrayInitializer ;; -- This PARAMETER DECLARATION rule is not used in optionalParameterDeclarationList, -- and lacks the ellipsis possibility & handling. It's used in catchClause -- and in forControl. parameterModifiers=optionalModifiers type=type variableName=identifier declaratorBrackets=optionalDeclaratorBrackets -> parameterDeclaration ;; -- This rule, admittedly, runs deep into implementation details. -- But anyways, it helps transforming the ugly representation of variable -- declarations in forControl and catchClause to the standard format. Unity! 0 [: VariableDeclaratorAst* declarator = create(); declarator->variableName = parameterDeclaration->variableName; declarator->declaratorBrackets = parameterDeclaration->declaratorBrackets; declarator->initializer = rest ? rest->firstInitializer : 0; declaratorSequence = snoc(declaratorSequence, declarator, memoryPool); if (rest && rest->variableDeclaratorSequence) { const KDevPG::ListNode *__it = rest->variableDeclaratorSequence->front(), *__end = __it; do { declaratorSequence = snoc(declaratorSequence, __it->element, memoryPool); __it = __it->next; } while (__it != __end); } :] data=variableDeclarationData[ parameterDeclaration->parameterModifiers, parameterDeclaration->type, declaratorSequence ] -> variableDeclarationSplitData [ argument temporary node parameterDeclaration: parameterDeclaration; argument temporary node rest: variableDeclarationRest; temporary node #declarator: variableDeclarator; ] ;; -- The (embedded) STATEMENT is a central point of the grammar, -- even if delegating most of the work to its children. ( block=block -- more blockStatements within {} braces | assertStatement=assertStatement | ifStatement=ifStatement | forStatement=forStatement | whileStatement=whileStatement | doWhileStatement=doWhileStatement | tryStatement=tryStatement | switchStatement=switchStatement | synchronizedStatement=synchronizedStatement | returnStatement=returnStatement | throwStatement=throwStatement | breakStatement=breakStatement | continueStatement=continueStatement | SEMICOLON | ?[: LA(2).kind == Token_COLON :] labeledStatement=labeledStatement | -- method call, assignment, etc.: expressionStatement=statementExpression SEMICOLON ) -> embeddedStatement ;; -- Simple one-rule statements: ASSERT condition=expression (COLON message=expression | 0) SEMICOLON -> assertStatement ;; IF LPAREN condition=expression RPAREN ifBody=embeddedStatement (ELSE elseBody=embeddedStatement | 0) -- the traditional "dangling-else" conflict: -- kdevelop-pg generates proper code here, matching as soon as possible. -> ifStatement ;; WHILE LPAREN condition=expression RPAREN body=embeddedStatement -> whileStatement ;; DO body=embeddedStatement WHILE LPAREN condition=expression RPAREN SEMICOLON -> doWhileStatement ;; SYNCHRONIZED LPAREN lockedType=expression RPAREN synchronizedBody=block -> synchronizedStatement ;; RETURN (returnExpression=expression | 0) SEMICOLON -> returnStatement ;; THROW exception=expression SEMICOLON -> throwStatement ;; BREAK (label=identifier | 0) SEMICOLON -> breakStatement ;; CONTINUE (label=identifier | 0) SEMICOLON -> continueStatement ;; label=identifier COLON statement=embeddedStatement -> labeledStatement ;; -- The TRY STATEMENT, also known as try/catch/finally block. TRY tryBody=block ( (#catchClause=catchClause)+ (FINALLY finallyBody=block | 0) | FINALLY finallyBody=block ) -> tryStatement ;; CATCH LPAREN exceptionParameter:parameterDeclaration RPAREN exceptionDeclaration=variableDeclarationSplitData[exceptionParameter, 0] body=block -> catchClause ;; -- The SWITCH STATEMENT, consisting of a header and multiple -- "case x:" or "default:" switch statement groups. SWITCH LPAREN switchExpression=expression RPAREN LBRACE try/recover(#switchSection=switchSection)* RBRACE -> switchStatement ;; (#label=switchLabel)+ try/recover(#statement=blockStatement)* -> switchSection ;; ( CASE caseExpression=expression [: (*yynode)->branchType = BranchCase; :] | DEFAULT [: (*yynode)->branchType = BranchDefault; :] ) COLON -> switchLabel [ member variable branchType: BranchTypeEnum; ] ;; -- The FOR STATEMENT, including its problematic child forControl. FOR LPAREN forControl=forControl RPAREN forBody=embeddedStatement -> forStatement ;; -- The FOR CONTROL is the three statements inside the for(...) parentheses, -- or the alternative foreach specifier. It has the same problematic conflict -- between parameterDeclaration and expression that blockStatement also has -- and which is only solvable with arbitrary-length LL(k) and therefore needs -- backtracking with try/rollback. ( try/rollback( variableDeclarationStartOrForeachParameter:parameterDeclaration -- "int i" ( -- foreach: int i : intList.values() ?[: compatibilityMode() >= Java15Compatibility :] COLON iterableExpression:expression foreachDeclaration=foreachDeclarationData[ variableDeclarationStartOrForeachParameter, iterableExpression ] | -- traditional: int i = 0; i < size; i++ variableDeclarationRest:variableDeclarationRest -- "= 0" variableDeclaration=variableDeclarationSplitData[ variableDeclarationStartOrForeachParameter, variableDeclarationRest ] traditionalForRest=forClauseTraditionalRest -- "; i < size; i++" ) ) catch( #statementExpression=statementExpression @ COMMA traditionalForRest=forClauseTraditionalRest ) | traditionalForRest=forClauseTraditionalRest -- only starting with ";" ) -> forControl ;; SEMICOLON (forCondition=expression | 0) SEMICOLON -- "i < size;" (#forUpdateExpression=statementExpression @ COMMA | 0) -- "i++" -> forClauseTraditionalRest ;; 0 -> foreachDeclarationData [ argument member node foreachParameter: parameterDeclaration; argument member node iterableExpression: expression; ] ;; -- EXPRESSIONS -- Note that most of these expressions follow the pattern -- thisLevelExpression : -- nextHigherPrecedenceExpression @ OPERATOR -- -- The operators in java have the following precedences: -- lowest (13) Assignment = *= /= %= += -= <<= >>= >>>= &= ^= |= -- (12) Conditional ?: -- (11) Conditional OR || -- (10) Conditional AND && -- ( 9) Logical OR | -- ( 8) Logical XOR ^ -- ( 7) Logical AND & -- ( 6) Equality == != -- ( 5) Relational and type-testing < <= > >= -- ( 4) Shift << >> -- ( 3) Additive +(binary) -(binary) -- ( 2) Multiplicative * / % -- ( 1) Unary ++ -- +(unary) -(unary) ~ ! (type)x -- Primary f(x) x.y a[x] -- highest new () (explicit parenthesis) -- -- the last two are not usually on a precedence chart; they are put in -- to point out that "new" has a higher precedence than ".", so you -- can validly use -- new Frame().show() -- A STATEMENT EXPRESSION may not contain certain subsets of expression, -- but it's just not feasible for LL(k) parsers to filter them out. expression=expression -> statementExpression ;; -- So this is the actual EXPRESSION, also known as assignment expression. conditionalExpression=conditionalExpression ( ( ASSIGN [: (*yynode)->assignmentOperator = AssignmentOperatorPlain; :] | PLUS_ASSIGN [: (*yynode)->assignmentOperator = AssignmentOperatorPlus; :] | MINUS_ASSIGN [: (*yynode)->assignmentOperator = AssignmentOperatorMinus; :] | STAR_ASSIGN [: (*yynode)->assignmentOperator = AssignmentOperatorStar; :] | SLASH_ASSIGN [: (*yynode)->assignmentOperator = AssignmentOperatorSlash; :] | BIT_AND_ASSIGN [: (*yynode)->assignmentOperator = AssignmentOperatorBitAnd; :] | BIT_OR_ASSIGN [: (*yynode)->assignmentOperator = AssignmentOperatorBitOr; :] | BIT_XOR_ASSIGN [: (*yynode)->assignmentOperator = AssignmentOperatorBitXOr; :] | REMAINDER_ASSIGN [: (*yynode)->assignmentOperator = AssignmentOperatorRemainder; :] | LSHIFT_ASSIGN [: (*yynode)->assignmentOperator = AssignmentOperatorLShift; :] | SIGNED_RSHIFT_ASSIGN [: (*yynode)->assignmentOperator = AssignmentOperatorRShiftSigned; :] | UNSIGNED_RSHIFT_ASSIGN [: (*yynode)->assignmentOperator = AssignmentOperatorRShiftUnsigned; :] ) assignmentExpression=expression | 0 [: (*yynode)->assignmentOperator = AssignmentOperatorNone; :] ) -> expression [ member variable assignmentOperator: AssignmentOperatorEnum; ] ;; logicalOrExpression=logicalOrExpression ( QUESTION ifExpression=expression COLON elseExpression=conditionalExpression | 0 ) -> conditionalExpression ;; #expression=logicalAndExpression @ LOG_OR -> logicalOrExpression ;; #expression=bitOrExpression @ LOG_AND -> logicalAndExpression ;; #expression=bitXOrExpression @ BIT_OR -> bitOrExpression ;; #expression=bitAndExpression @ BIT_XOR -> bitXOrExpression ;; #expression=equalityExpression @ BIT_AND -> bitAndExpression ;; expression=relationalExpression (#additionalExpression=equalityExpressionRest)* -> equalityExpression ;; ( EQUAL [: (*yynode)->equalityOperator = EqualityOperatorEqual; :] | NOT_EQUAL [: (*yynode)->equalityOperator = EqualityOperatorNotEqual; :] ) expression=relationalExpression -> equalityExpressionRest [ member variable equalityOperator: EqualityOperatorEnum; ] ;; expression=shiftExpression ( (#additionalExpression=relationalExpressionRest)+ | INSTANCEOF instanceofType=type | 0 ) -> relationalExpression ;; ( LESS_THAN [: (*yynode)->relationalOperator = RelationalOperatorLessThan; :] | GREATER_THAN [: (*yynode)->relationalOperator = RelationalOperatorGreaterThan; :] | LESS_EQUAL [: (*yynode)->relationalOperator = RelationalOperatorLessEqual; :] | GREATER_EQUAL [: (*yynode)->relationalOperator = RelationalOperatorGreaterEqual; :] ) expression=shiftExpression -> relationalExpressionRest [ member variable relationalOperator: RelationalOperatorEnum; ] ;; expression=additiveExpression (#additionalExpression=shiftExpressionRest)* -> shiftExpression ;; ( LSHIFT [: (*yynode)->shiftOperator = ShiftOperatorLShift; :] | SIGNED_RSHIFT [: (*yynode)->shiftOperator = ShiftOperatorRShiftSigned; :] | UNSIGNED_RSHIFT [: (*yynode)->shiftOperator = ShiftOperatorRShiftUnsigned; :] ) expression=additiveExpression -> shiftExpressionRest [ member variable shiftOperator: ShiftOperatorEnum; ] ;; expression=multiplicativeExpression (#additionalExpression=additiveExpressionRest)* -> additiveExpression ;; ( PLUS [: (*yynode)->additiveOperator = AdditiveOperatorPlus; :] | MINUS [: (*yynode)->additiveOperator = AdditiveOperatorMinus; :] ) expression=multiplicativeExpression -> additiveExpressionRest [ member variable additiveOperator: AdditiveOperatorEnum; ] ;; expression=unaryExpression (#additionalExpression=multiplicativeExpressionRest)* -> multiplicativeExpression ;; ( STAR [: (*yynode)->multiplicativeOperator = MultiplicativeOperatorStar; :] | SLASH [: (*yynode)->multiplicativeOperator = MultiplicativeOperatorSlash; :] | REMAINDER [: (*yynode)->multiplicativeOperator = MultiplicativeOperatorRemainder; :] ) expression=unaryExpression -> multiplicativeExpressionRest [ member variable multiplicativeOperator: MultiplicativeOperatorEnum; ] ;; -- The UNARY EXPRESSION and the its not-plusminus part are one rule in the -- specification, but split apart for better castExpression lookahead results. ( INCREMENT unaryExpression=unaryExpression [: (*yynode)->ruleType = UnaryExpressionIncrement; :] | DECREMENT unaryExpression=unaryExpression [: (*yynode)->ruleType = UnaryExpressionDecrement; :] | MINUS unaryExpression=unaryExpression [: (*yynode)->ruleType = UnaryExpressionMinus; :] | PLUS unaryExpression=unaryExpression [: (*yynode)->ruleType = UnaryExpressionPlus; :] | unaryExpressionNotPlusMinus=unaryExpressionNotPlusMinus [: (*yynode)->ruleType = UnaryExpressionNotPlusMinus; :] ) -> unaryExpression [ member variable ruleType: UnaryExpressionPlusMinusEnum; ] ;; -- So, up till now this was the easy stuff. Here comes another severe conflict -- in the grammar that can only be solved with LL(k). -- The conflict in this rule is the ambiguity between type casts (which -- can be arbitrary class names within parentheses) and primaryExpressions, -- which can also look that way from an LL(1) perspective. -- Using backtracking with try/rollback solves the problem. ( TILDE bitwiseNotExpression=unaryExpression [: (*yynode)->ruleType = UnaryExpressionBitwiseNot; :] | BANG logical_not_expression=unaryExpression [: (*yynode)->ruleType = UnaryExpressionLogicalNot; :] | try/rollback( castExpression=castExpression [: (*yynode)->ruleType = UnaryExpressionCast; :] ) catch ( primaryExpression=primaryExpression (#postfixOperator=postfixOperator)* [: (*yynode)->ruleType = UnaryExpressionPrimary; :] ) ) -> unaryExpressionNotPlusMinus [ member variable ruleType: UnaryExpressionNotPlusMinusEnum; ] ;; LPAREN ( builtInType=optionalArrayBuiltInType RPAREN builtinCastedExpression=unaryExpression | classType=classType RPAREN classCastedExpression=unaryExpressionNotPlusMinus ) -> castExpression ;; INCREMENT [: (*yynode)->postfixOperator = PostfixOperatorIncrement; :] | DECREMENT [: (*yynode)->postfixOperator = PostfixOperatorDecrement; :] -> postfixOperator [ member variable postfixOperator: PostfixOperatorEnum; ] ;; -- PRIMARY EXPRESSIONs: qualified names, array expressions, -- method invocation, post increment/decrement primaryAtom=primaryAtom (#selector=primarySelector)* -> primaryExpression ;; -- SELECTORs appended to a primary atom can provide access to ".this" or -- ".super", create classes with ".new ClassName(...)", call methods with -- ".methodName(...)", access a member variable with ".variableName", -- the expression's class info with ".class" and access arrays with "[...]". ( DOT ( CLASS classAccess=classAccessData -- empty rules, for having | THIS thisAccess=thisAccessData -- a default visitor auto-generated. | newExpression=newExpression | ?[: LA(2).kind != Token_LPAREN :] -- member variable access identifier:identifier -- (no method call) simpleNameAccess=simpleNameAccessData[ identifier ] | -- method calls (including the "super" ones) may have type arguments ( ?[: compatibilityMode() >= Java15Compatibility :] typeArguments:nonWildcardTypeArguments | 0 ) ( SUPER superSuffix:superSuffix superAccess=superAccessData[ typeArguments, superSuffix ] | identifier:identifier LPAREN arguments:optionalArgumentList RPAREN methodCall=methodCallData[ typeArguments, identifier, arguments ] ) ) | arrayAccess=arrayAccess ) -> primarySelector ;; LBRACKET arrayIndexExpression=expression RBRACKET -> arrayAccess ;; -- SUPER SUFFIX: a call to either a constructor, a method or -- a member variable of the super class. ( LPAREN constructorArguments=optionalArgumentList RPAREN -- constructor call | DOT -- member access ( ?[: LA(2).kind != Token_LPAREN :] -- member variable access (no method call) identifier:identifier simpleNameAccess=simpleNameAccessData[ identifier ] | -- method access (looks like super.methodName(...) in the end) ( ?[: compatibilityMode() >= Java15Compatibility :] typeArguments:nonWildcardTypeArguments | 0 ) identifier:identifier LPAREN arguments:optionalArgumentList RPAREN methodCall=methodCallData[ typeArguments, identifier, arguments ] ) ) -> superSuffix ;; -- PRIMARY ATOM: the basic element of a primary expression, -- and expressions in general ( literal=literal | newExpression=newExpression | LPAREN parenthesisExpression=expression RPAREN | -- stuff like int.class or int[].class builtInTypeDotClass=builtInTypeDotClass | THIS ( LPAREN arguments:optionalArgumentList RPAREN thisCall=thisCallData[ 0 /* no type arguments */, arguments ] | thisAccess=thisAccessData -- empty rule, for having a default visitor ) | SUPER superSuffix:superSuffix superAccess=superAccessData[ 0 /* no type arguments */, superSuffix ] | ?[: compatibilityMode() >= Java15Compatibility :] -- generic method invocation with type arguments: typeArguments:nonWildcardTypeArguments ( SUPER superSuffix:superSuffix superAccess=superAccessData[ typeArguments, superSuffix ] | THIS LPAREN arguments:optionalArgumentList RPAREN thisCall=thisCallData[ typeArguments, arguments ] | identifier:identifier LPAREN arguments:optionalArgumentList RPAREN methodCall=methodCallData[ typeArguments, identifier, arguments ] ) | try/rollback( -- stuff like narf.zoht[][].class arrayTypeDotClass=arrayTypeDotClass ) catch ( -- type names (normal) - either pure or as method identifier:identifier ( LPAREN arguments:optionalArgumentList RPAREN methodCall=methodCallData[ 0 /* no type arguments */, identifier, arguments ] | simpleNameAccess=simpleNameAccessData[ identifier ] ) ) ) -> primaryAtom ;; builtInType=optionalArrayBuiltInType DOT CLASS -> builtInTypeDotClass ;; qualifiedIdentifier=qualifiedIdentifier declaratorBrackets=mandatoryDeclaratorBrackets DOT CLASS -> arrayTypeDotClass ;; 0 -> methodCallData [ argument member node typeArguments: nonWildcardTypeArguments; argument member node methodName: identifier; argument member node arguments: optionalArgumentList; ] ;; 0 -> thisCallData [ argument member node typeArguments: nonWildcardTypeArguments; argument member node arguments: optionalArgumentList; ] ;; 0 -> thisAccessData ;; -- probably the emptiest rule in the whole grammar ;) -- but kdev-pg creates a default visitor method, and that's why it's there 0 -> classAccessData ;; -- hm maybe this rule is equally empty... 0 -> superAccessData [ argument member node typeArguments: nonWildcardTypeArguments; argument member node superSuffix: superSuffix; ] ;; 0 -> simpleNameAccessData [ argument member node name: identifier; ] ;; -- NEW EXPRESSIONs are allocations of new types or arrays. NEW ( ?[: compatibilityMode() >= Java15Compatibility :] typeArguments=nonWildcardTypeArguments | 0 ) type=nonArrayType ( LPAREN classConstructorArguments=optionalArgumentList RPAREN (classBody=classBody | 0) | arrayCreatorRest=arrayCreatorRest ) -> newExpression ;; -- This array creator rest can be either -- a.) empty brackets with an optional initializer (e.g. "[][]{exp,exp}") or -- b.) at least one filled bracket, afterwards any amount of empty ones ( ?[: LA(2).kind == Token_RBRACKET :] mandatoryDeclaratorBrackets=mandatoryDeclaratorBrackets arrayInitializer=variableArrayInitializer | LBRACKET #indexExpression=expression RBRACKET ( 0 [: if (LA(2).kind == Token_RBRACKET) { break; } :] -- exit the loop when noticing declarator brackets LBRACKET #indexExpression=expression RBRACKET )* optionalDeclaratorBrackets=optionalDeclaratorBrackets ) -> arrayCreatorRest ;; -- All kinds of rules for types here. -- A TYPE is a type name with optionally appended brackets -- (which would make it an array type). classType=classType | builtInType=optionalArrayBuiltInType -> type ;; type=classOrInterfaceTypeName declaratorBrackets=optionalDeclaratorBrackets -> classType ;; type=builtInType declaratorBrackets=optionalDeclaratorBrackets -> optionalArrayBuiltInType ;; type=builtInType declaratorBrackets=mandatoryDeclaratorBrackets -> mandatoryArrayBuiltInType ;; -- A NON-ARRAY TYPE is just a type name, without appended brackets classOrInterfaceType=classOrInterfaceTypeName | builtInType=builtInType -> nonArrayType ;; -- The primitive types. The Java specification doesn't include void here, -- but the ANTLR grammar works that way, and so does this one. VOID [: (*yynode)->type = BuiltInTypeVoid; :] | BOOLEAN [: (*yynode)->type = BuiltInTypeBoolean; :] | BYTE [: (*yynode)->type = BuiltInTypeByte; :] | CHAR [: (*yynode)->type = BuiltInTypeChar; :] | SHORT [: (*yynode)->type = BuiltInTypeShort; :] | INT [: (*yynode)->type = BuiltInTypeInt; :] | FLOAT [: (*yynode)->type = BuiltInTypeFloat; :] | LONG [: (*yynode)->type = BuiltInTypeLong; :] | DOUBLE [: (*yynode)->type = BuiltInTypeDouble; :] -> builtInType [ member variable type: BuiltInTypeEnum; ] ;; #part=classOrInterfaceTypeNamePart @ DOT -> classOrInterfaceTypeName ;; identifier=identifier ( ?[: compatibilityMode() >= Java15Compatibility :] typeArguments=typeArguments | 0 ) -> classOrInterfaceTypeNamePart ;; -- QUALIFIED identifiers are either qualified ones or raw identifiers. #name=identifier @ DOT -> qualifiedIdentifier ;; #name=identifier [: (*yynode)->hasStar = false; :] ( DOT ( #name=identifier | STAR [: (*yynode)->hasStar = true; break; :] -- break -> no more identifiers after the star ) )* -> qualifiedIdentifierWithOptionalStar [ member variable hasStar: bool; ] ;; -- Declarator brackets are part of a type specification, like String[][]. -- They are always empty, only have to be counted. ( LBRACKET RBRACKET [: (*yynode)->bracketCount++; :] )* -> optionalDeclaratorBrackets [ member variable bracketCount: int; ] ;; ( LBRACKET RBRACKET [: (*yynode)->bracketCount++; :] )+ -> mandatoryDeclaratorBrackets [ member variable bracketCount: int; ] ;; -- MODIFIERs for Java classes, interfaces, class/instance vars and methods. -- Sometimes not all of them are valid, but that has to be checked manually -- after running the parser. The ANTLR grammar also does it this way. -- All the occurring modifiers are stored together in the "modifiers" -- AST node member as flags, except for the annotations who get their own list. ( PRIVATE [: (*yynode)->modifiers |= ModifierPrivate; :] | PUBLIC [: (*yynode)->modifiers |= ModifierPublic; :] | PROTECTED [: (*yynode)->modifiers |= ModifierProtected; :] | STATIC [: (*yynode)->modifiers |= ModifierStatic; :] | TRANSIENT [: (*yynode)->modifiers |= ModifierTransient; :] | FINAL [: (*yynode)->modifiers |= ModifierFinal; :] | ABSTRACT [: (*yynode)->modifiers |= ModifierAbstract; :] | NATIVE [: (*yynode)->modifiers |= ModifierNative; :] -- Neither in the Java spec nor in the JavaCC grammar, just in the ANTLR one: -- | ModThreadsafe=THREADSAFE | SYNCHRONIZED [: (*yynode)->modifiers |= ModifierSynchronized; :] | VOLATILE [: (*yynode)->modifiers |= ModifierVolatile; :] | STRICTFP [: (*yynode)->modifiers |= ModifierStrictFP; :] | -- A modifier may be any annotation (e.g. @bla), but not @interface. -- This condition resolves the conflict between modifiers -- and annotation type declarations: 0 [: if (yytoken == Token_AT && LA(2).kind == Token_INTERFACE) { break; } :] try/recover(#modifierAnnotation=annotation) )* -> optionalModifiers [ member variable modifiers: unsigned int; ] ;; ident=IDENTIFIER -> identifier ;; ( TRUE [: (*yynode)->literalType = LiteralTrue; :] | FALSE [: (*yynode)->literalType = LiteralFalse; :] | NULL [: (*yynode)->literalType = LiteralNull; :] | integerLiteral=INTEGER_LITERAL [: (*yynode)->literalType = LiteralInteger; :] | floatingPointLiteral=FLOATING_POINT_LITERAL [: (*yynode)->literalType = LiteralFloatingPoint; :] | characterLiteral=CHARACTER_LITERAL [: (*yynode)->literalType = LiteralCharacter; :] | stringLiteral=STRING_LITERAL [: (*yynode)->literalType = LiteralString; :] ) -> literal [ member variable literalType: LiteralTypeEnum; ] ;; ----------------------------------------------------------------- -- Code segments copied to the implementation (.cpp) file. -- If existent, kdevelop-pg's current syntax requires this block -- to occur at the end of the file. ----------------------------------------------------------------- [: #include "javalexer.h" #include namespace java { void Parser::tokenize( char *contents ) { Lexer lexer( this, contents ); int kind = Parser::Token_EOF; do { kind = lexer.yylex(); //std::cerr << lexer.YYText() << std::endl; //" "; // debug output if ( !kind ) // when the lexer returns 0, the end of file is reached kind = Parser::Token_EOF; Parser::Token &t = this->tokenStream->push(); t.kind = kind; t.begin = lexer.tokenBegin(); t.end = lexer.tokenEnd(); } while ( kind != Parser::Token_EOF ); this->yylex(); // produce the look ahead token } Parser::JavaCompatibilityMode Parser::compatibilityMode() { return m_compatibilityMode; } void Parser::setCompatibilityMode( Parser::JavaCompatibilityMode mode ) { m_compatibilityMode = mode; } Parser::ParserState *Parser::copyCurrentState() { ParserState *state = new ParserState(); state->ltCounter = m_state.ltCounter; return state; } void Parser::restoreState( Parser::ParserState *state ) { m_state.ltCounter = state->ltCounter; } } // end of namespace java :] diff --git a/parser/java_io.cpp b/parser/java_io.cpp index 84d486b..d4d6c4e 100644 --- a/parser/java_io.cpp +++ b/parser/java_io.cpp @@ -1,75 +1,75 @@ /***************************************************************************** * Copyright (c) 2005, 2006 Jakob Petsovits * * * * This program 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 grammar 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 * * Lesser 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. * *****************************************************************************/ // This file is meant to be specific to the framework in which the parser // operates, and is likely to be adapted for different environments. -// Specifically, the error output might not always go to kDebug(), +// Specifically, the error output might not always go to qDebug(), // but will rather be placed as items inside some listbox. #include "javaparser.h" #include "javalexer.h" #include -#include +#include // void print_token_environment(java::Parser* parser); namespace java { void Parser::reportProblem( Parser::ProblemType type, const QString& message ) { if (type == Error) { - kDebug() << "** ERROR:" << message; + qDebug() << "** ERROR:" << message; } else if (type == Warning) { - kDebug() << "** WARNING:" << message; + qDebug() << "** WARNING:" << message; } else if (type == Info) { - kDebug() << "** Info:" << message; + qDebug() << "** Info:" << message; } } // custom error recovery void Parser::expectedToken(int /*expected*/, qint64 /*where*/, const QString& name) { // print_token_environment(this); reportProblem( Parser::Error, QString("Expected token ``%1''").arg(name) //+ QString(" instead of ``%1''").arg(current_token_text) ); } void Parser::expectedSymbol(int /*expected_symbol*/, const QString& name) { // print_token_environment(this); reportProblem( Parser::Error, QString("Expected symbol ``%1''").arg(name) //+ QString(" instead of ``%1''").arg(current_token_text) ); } } // end of namespace java diff --git a/parser/javalexer.h b/parser/javalexer.h index 4fe7d83..59c0b09 100644 --- a/parser/javalexer.h +++ b/parser/javalexer.h @@ -1,68 +1,68 @@ /***************************************************************************** * Copyright (c) 2005, 2006 Jakob Petsovits * * * * This program 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 grammar 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 * * Lesser 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 "javaparser.h" -#include "javaparserexport.h" +#include "javaparser_export.h" #include #ifndef DONT_INCLUDE_FLEXLEXER -#include "FlexLexer.h" +#include #endif // The YY_USER_ACTION macro is called whenever a token is found by Flex #define YY_USER_ACTION \ m_tokenBegin = m_tokenEnd; \ m_tokenEnd += yyleng; namespace java { class KDEVJAVAPARSER_EXPORT Lexer : public yyFlexLexer { public: Lexer( java::Parser *parser, char *contents ); void restart( java::Parser *parser, char *contents ); int yylex(); char *contents() { return m_contents; } std::size_t tokenBegin() { return m_tokenBegin; } std::size_t tokenEnd() { return m_tokenEnd; } protected: // custom input, replacing the Flex default input stdin virtual int LexerInput( char *buf, int max_size ); // dismisses any lexer output (which should not happen anyways) virtual void LexerOutput( const char * /*buf*/, int /*max_size*/ ) { return; } virtual void LexerError( const char */*msg*/ ) { return; } private: java::Parser* m_parser; char *m_contents; std::size_t m_tokenBegin, m_tokenEnd; std::size_t m_currentOffset; KDevPG::LocationTable *m_locationTable; }; } // end of namespace java // kate: space-indent on; indent-width 4; tab-width 4; replace-tabs on diff --git a/parser/javaparserexport.h b/parser/javaparserexport.h deleted file mode 100644 index 5ad8ac5..0000000 --- a/parser/javaparserexport.h +++ /dev/null @@ -1,36 +0,0 @@ -/*************************************************************************** - * This file is part of KDevelop * - * Copyright 2007 Andreas Pakulat * - * * - * This program 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 program 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 General Public License for more details. * - * * - * You should have received a copy of the GNU Library General Public * - * License along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ - -#ifndef JAVAPARSEREXPORT_H -#define JAVAPARSEREXPORT_H - -/* needed for KDE_EXPORT macros */ -#include - -#ifndef KDEVJAVAPARSER_EXPORT -# ifdef MAKE_KDEVJAVAPARSER_LIB -# define KDEVJAVAPARSER_EXPORT KDE_EXPORT -# else -# define KDEVJAVAPARSER_EXPORT KDE_IMPORT -# endif -#endif - -#endif - diff --git a/parser/parsesession.h b/parser/parsesession.h index fec2b81..d9a2299 100644 --- a/parser/parsesession.h +++ b/parser/parsesession.h @@ -1,82 +1,82 @@ /* * This file is part of KDevelop * * Copyright (C) 2006 Hamish Rodda * * This program 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 program 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef JAVA_PARSESESSION_H #define JAVA_PARSESESSION_H #include #include "javaparser.h" -#include "javaparserexport.h" -#include -#include +#include "javaparser_export.h" + +#include #include namespace java { typedef QPair SimpleUse; /// Contains everything needed to keep an AST useful once the rest of the parser /// has gone away. class KDEVJAVAPARSER_EXPORT ParseSession { public: ParseSession(); ~ParseSession(); /** * Return the position (\a line%, \a column%) of the \a offset in the file. * * \note the line starts from 0. */ KDevelop::CursorInRevision positionAt( qint64 offset ) const; void setContents( const QByteArray& contents ); const char *contents() const; KDevelop::IndexedString m_document; qint64 size() const; Parser::memoryPoolType *memoryPool; KDevPG::TokenStream *tokenStream; Parser::JavaCompatibilityMode compatibilityMode; QString symbol(qint64 token) const; /// This saves memory by sharing the strings using a global string repository /// \note Unimplemented QString unify(const QString& str) const; /// @TODO implement this void mapAstUse(AstNode* node, const SimpleUse& use) { Q_UNUSED(node); Q_UNUSED(use); } private: QByteArray m_contents; }; } // end of namespace java #endif diff --git a/settings/CMakeLists.txt b/settings/CMakeLists.txt index 45a39df..9ffbb4f 100644 --- a/settings/CMakeLists.txt +++ b/settings/CMakeLists.txt @@ -1,27 +1,18 @@ include_directories( ${CMAKE_SOURCE_DIR} - ${KDE4_INCLUDES} - ${KDEVPLATFORM_INCLUDE_DIR} ) set( javasettings_cfg_SRCS javapreferences.cpp ) set( javasettings_cfg_UI javasettings.ui ) -kde4_add_ui_files( javasettings_cfg_SRCS ${javasettings_cfg_UI} ) -kde4_add_kcfg_files( javasettings_cfg_SRCS javaconfig.kcfgc ) -kde4_add_plugin( kcm_kdev_javasettings ${javasettings_cfg_SRCS} ) -target_link_libraries( kcm_kdev_javasettings ${KDE4_KUTILS_LIBS} ${KDE4_KDEUI_LIBS} ${KDE4_KIO_LIBS} ${KDEVPLATFORM_INTERFACES_LIBRARIES} ) +ki18n_wrap_ui( javasettings_cfg_SRCS ${javasettings_cfg_UI} ) +kconfig_add_kcfg_files( javasettings_cfg_SRCS javaconfig.kcfgc ) +add_library(kdev_javasettings OBJECT ${javasettings_cfg_SRCS}) +target_link_libraries(kdev_javasettings KDev::Util) -install( TARGETS - kcm_kdev_javasettings - DESTINATION ${PLUGIN_INSTALL_DIR} ) - -install( FILES - kcm_kdev_javasettings.desktop - DESTINATION ${SERVICES_INSTALL_DIR} ) diff --git a/settings/javapreferences.cpp b/settings/javapreferences.cpp index b680a39..14edbbf 100644 --- a/settings/javapreferences.cpp +++ b/settings/javapreferences.cpp @@ -1,68 +1,57 @@ /* KDevelop Project Settings * * Copyright 2006 Matt Rogers * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "javapreferences.h" - -#include - -#include -#include - #include "javaconfig.h" +#include #include "ui_javasettings.h" -namespace KDevelop +JavaPreferences::JavaPreferences(QWidget* parent) + : ConfigPage(nullptr, JavaSettings::self(), parent) + , m_settings(new Ui::JavaSettings) { + m_settings->setupUi(this); +} -K_PLUGIN_FACTORY(JavaPreferencesFactory, registerPlugin();) -K_EXPORT_PLUGIN(JavaPreferencesFactory( KAboutData("kcm_kdev_bgsettings", "kdevplatform", ki18n("Java Support Settings"), "0.1"))) - +JavaPreferences::~JavaPreferences( ) +{} -JavaPreferences::JavaPreferences( QWidget *parent, const QVariantList &args ) - : KCModule( JavaPreferencesFactory::componentData(), parent, args ) +QString JavaPreferences::name() const { - - QVBoxLayout * l = new QVBoxLayout( this ); - QWidget* w = new QWidget; - preferencesDialog = new Ui::JavaSettings; - preferencesDialog->setupUi( w ); - - l->addWidget( w ); - - addConfig( JavaSettings::self(), w ); - - load(); + return i18n("Java Support"); } -JavaPreferences::~JavaPreferences( ) +QString JavaPreferences::fullName() const { - delete preferencesDialog; + return i18n("Configure Java Support settings"); } -void JavaPreferences::save() +QIcon JavaPreferences::icon() const { - KCModule::save(); + return QIcon::fromTheme(QStringLiteral("application-x-java")); } -} -#include "javapreferences.moc" +KDevelop::ConfigPage::ConfigPageType JavaPreferences::configPageType() const +{ + return ConfigPage::LanguageConfigPage; +} diff --git a/settings/javapreferences.h b/settings/javapreferences.h index e571bed..3216a04 100644 --- a/settings/javapreferences.h +++ b/settings/javapreferences.h @@ -1,59 +1,49 @@ /* KDevelop Java Support Settings * * Copyright 2006 Matt Rogers * Copyright 2007-2009 Hamish Rodda * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifndef KDEVJAVAPREFERENCES_H #define KDEVJAVAPREFERENCES_H -#include - -#include -#include +#include namespace Ui { class JavaSettings; } -namespace KDevelop -{ - -class JavaPreferences : public KCModule +class JavaPreferences : public KDevelop::ConfigPage { Q_OBJECT public: - JavaPreferences( QWidget *parent, const QVariantList &args ); + JavaPreferences(QWidget* parent); virtual ~JavaPreferences(); - virtual void save(); + QString name() const override; + QString fullName() const override; + QIcon icon() const override; - virtual KUrl localNonShareableFile() const - { - return KUrl::fromPath( - KStandardDirs::locate( "data", "kdevelop/data.kdev4" ) ); - } + KDevelop::ConfigPage::ConfigPageType configPageType() const override; private: - Ui::JavaSettings *preferencesDialog; - + QScopedPointer m_settings; }; -} #endif diff --git a/settings/javasettings.ui b/settings/javasettings.ui index 953ab88..909a6c2 100644 --- a/settings/javasettings.ui +++ b/settings/javasettings.ui @@ -1,52 +1,51 @@ JavaSettings 0 0 475 402 Java Source zip: kcm_java_source_zip Qt::Vertical 20 358 qPixmapFromMimeSource KUrlRequester QFrame -
kurlrequester.h
diff --git a/settings/kcm_kdev_javasettings.desktop b/settings/kcm_kdev_javasettings.desktop deleted file mode 100644 index 250d3cd..0000000 --- a/settings/kcm_kdev_javasettings.desktop +++ /dev/null @@ -1,65 +0,0 @@ -[Desktop Entry] -Icon=java -Type=Service -ServiceTypes=KCModule - -X-KDE-ModuleType=Library -X-KDE-Library=kcm_kdev_javasettings -X-KDE-FactoryName=kcm_kdev_javasettings -X-KDE-ParentApp=kdevplatform -X-KDE-ParentComponents=kdevplatform -X-KDE-CfgDlgHierarchy=GENERAL - -Name=Java Support -Name[bg]=Поддръжка на Java -Name[bs]=Podrška za jezik Java -Name[ca]=Implementació Java -Name[ca@valencia]=Implementació Java -Name[de]=Unterstützung für Java -Name[en_GB]=Java Support -Name[es]=Implementación de Java -Name[et]=Java toetus -Name[fi]=Java-tuki -Name[fr]=Prise en charge de Java -Name[ga]=Tacaíocht Java -Name[gl]=Soporte de Java -Name[hu]=Java támogatás -Name[it]=Supporto per Java -Name[ja]=Java サポート -Name[nds]=Java-Ünnerstütten -Name[nl]=Ondersteuning voor Java -Name[pa]=ਜਾਵਾ ਸਹਿਯੋਗ -Name[pl]=Obsługa Java -Name[pt]=Suporte para Java -Name[pt_BR]=Suporte a Java -Name[sk]=Podpora Javy -Name[sv]=Java-stöd -Name[tr]=Java Desteği -Name[uk]=Підтримка Java -Name[x-test]=xxJava Supportxx -Comment=Configure Java Support settings -Comment[bg]=Настройки на поддръжката на Java -Comment[bs]=Konfiguriši podršku za jezik Java -Comment[ca]=Configura els arranjaments de la implementació de Java -Comment[ca@valencia]=Configura els arranjaments de la implementació de Java -Comment[de]=Unterstützung für Java einrichten -Comment[en_GB]=Configure Java Support settings -Comment[es]=Configurar las preferencias de la implementación Java -Comment[et]=Java toetuse seadistamine -Comment[fi]=Java-tuen asetukset -Comment[fr]=Configure les paramètres pour la prise en charge de Java -Comment[ga]=Cumraigh socruithe Tacaíocht Java -Comment[gl]=Configuración do soporte de Java -Comment[hu]=Java támogatás beállításainak módosítása -Comment[it]=Configura le impostazioni per il supporto Java -Comment[ja]=Java サポートを設定します -Comment[nds]=Java-Ünnerstütten instellen -Comment[nl]=Instellingen voor Java-ondersteuning configureren -Comment[pl]=Konfiguruj ustawienia obsługi Java -Comment[pt]=Configurar as opções do Suporte para Java -Comment[pt_BR]=Configurar as opções do suporte para Java -Comment[sk]=Nastaviť nastavenia podpory Javy -Comment[sv]=Anpassa inställningar av Java-stöd -Comment[tr]=Java Desteği ayarlarını yapılandır -Comment[uk]=Налаштувати параметри підтримки Java -Comment[x-test]=xxConfigure Java Support settingsxx