/* Copyright 2007-2009 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. */ #ifndef CODECOMPLETIONCONTEXT_H #define CODECOMPLETIONCONTEXT_H #include #include #include "../cppduchain/typeconversion.h" #include "../cppduchain/expressionevaluationresult.h" #include #include "item.h" #include namespace KTextEditor { class View; class Cursor; } namespace KDevelop { class DUContext; class AbstractType; class CompletionTreeItem; typedef KSharedPtr CompletionTreeItemPointer; typedef QPair DeclAccessPair; } namespace Cpp { class OverloadResolutionFunction; class ImplementationHelperItem; #ifdef TEST_COMPLETION int expressionBefore( const QString& _text, int index ); #endif typedef QPair DeclarationDepthPair; /** * 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: ///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); virtual QList< KSharedPtr< KDevelop::CompletionTreeElement > > ungroupedElements(); typedef KSharedPtr Ptr; typedef OverloadResolutionFunction Function; typedef QList FunctionList; enum AccessType { NoMemberAccess, /// With NoMemberAccess, a global completion should be done MemberAccess, /// "Class." ArrowMemberAccess, /// "Class->" StaticMemberChoose, /// "Class::" MemberChoose, /// "Class->ParentClass::" 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() /// The following will never appear as initial accessType, but as a parentContext() FunctionCallAccess, /// "function(" BinaryOpFunctionCallAccess, /// "var1 {somebinaryoperator} " TemplateAccess, /// "bla<." ReturnAccess, /// "return " -- Takes into account return type CaseAccess, /// "case " -- Takes into account switch expression type NamespaceAccess }; /** * @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 * @param knownArgumentExpressions has no effect when firstContext is set * @param line Optional line that will be used to filter the macros * */ CodeCompletionContext(KDevelop::DUContextPointer context, const QString& text, const QString& followingText, const KDevelop::CursorInRevision& position, int depth = 0, const QStringList& knownArgumentExpressions = QStringList(), int line = -1 ); ~CodeCompletionContext(); /**In the case of recursive argument-hints, there may be a chain of parent-contexts, each for the higher argument-matching * The parentContext() should always have the access-operation FunctionCallAccess. * When a completion-list is computed, the members of the list can be highlighted that match the corresponding parentContext()->functions() function-argument, or parentContext()->additionalMatchTypes() * */ CodeCompletionContext* parentContext() const; ///@return the used access-operation AccessType accessType() const; ///@return the list of IndexedTypes that this CodeCompletionContext expects QList matchTypes(); /** * When the access-operation is a MemberAccess or ArrowMemberAccess, this * is the container that completion should happen in * (the code-completion should list its non-static content). * * When memberAccessOperation is StaticMemberChoose, the code-completion * should list all static members of this container. * * When memberAccessOperation is MemberChoose, it should be treated equivalently to MemberAccess. * * The type does not respect the member-access-operation, so * the code-completion may check whether the arrow-access was used correctly * and maybe do automatic correction. * @return the type of the container that should be completed in. * */ ExpressionEvaluationResult memberAccessContainer() const; /** * Returns the internal context of memberAccessContainer, if any. * * When memberAccessOperation is StaticMemberChoose, this returns all * fitting namespace-contexts. * *DUChain must be locked* * */ QSet memberAccessContainers() const; /** * When memberAccessOperation is FunctionCallAccess, * this returns all functions available for matching, together with the argument-number that should be matched. * * Operators are treated as functions, but there is special-cases that need to be treated, especially operator=(..), because that operator competes with normal type-conversion. * * To also respect builtin operators, the types returned by additionalMatchTypes() must be respected. * */ const FunctionList& functions() const; /// @return of the function name for this context. Also works for operators. QString functionName() const; /** * When memberAccessOperation is IncludeListAccess, then this contains all the files to be listed. * */ QList includeItems() const; int pointerConversions() const; QString followingText() const; void setFollowingText(QString str); bool isConstructorInitialization(); ///If this is a function call context, this returns the arguments to the function that are already known QList knownArgumentTypes() const; ///Returns position of the argument being matched int matchPosition() const; #ifndef TEST_COMPLETION private: #endif enum OnlyShow { ShowAll, ShowIntegralConstants, // compile-time integral constants and related items (scopes, ...) ShowTypes, ShowSignals, ShowSlots, ShowVariables, ShowImplementationHelpers }; #ifdef TEST_COMPLETION OnlyShow onlyShow() { return m_onlyShow; }; private: #endif ///Preprocess m_text (replace macros with their body etc.) void preprocessText(int line); ///looks at @param str to determine current context ///*DUChain must be locked* AccessType findAccessType(const QString &str) const; ///Get local class from m_duContext, if available ///*DUChain must be locked* DUContextPointer findLocalClass() const; ///Find if this context should limit completions to certain kinds ///*DUChain must be locked* OnlyShow findOnlyShow(const QString &accessStr) const; ///Get the types for m_knownArgumentExpressions ///*DUChain must be locked* QList getKnownArgumentTypes() const; ///Looks in m_text to find @param expression, @param expressionPrefix, ///and whether the expression @param istypeprefix ///*DUChain must be locked* void findExpressionAndPrefix(QString &expression, QString &expressionPrefix, bool &isTypePrefix) const; ///Create and return a parent context for the given @param expressionPrefix KSharedPtr getParentContext(const QString &expressionPrefix) const; ///Evaluate m_expression ExpressionEvaluationResult evaluateExpression() const; ///Remove unary operators from the end of m_text, setting m_pointerConversionsBeforeMatching accordingly void skipUnaryOperators(QString &str, int &pointerConversions) const; ///test if the context is valid for its accessType bool testContextValidity(const QString &expressionPrefix, const QString &accessStr) const; /** * Specialized processing for access types * *DUChain must be locked for these functions* **/ void processArrowMemberAccess(); void processFunctionCallAccess(); void processAllMemberAccesses(); ///Whether or not this context should add parent items bool shouldAddParentItems(bool fullCompletion); /** * Item creation functions for various completion types **/ ///*DUChain must be locked* QList keywordCompletionItems(); QList memberAccessCompletionItems(const bool& shouldAbort); QList returnAccessCompletionItems(); QList caseAccessCompletionItems(); QList templateAccessCompletionItems(); QList functionAccessCompletionItems(bool fullCompletion); QList binaryFunctionAccessCompletionItems(bool fullCompletion); ///*DUChain must _not_ be locked* QList commonFunctionAccessCompletionItems(bool fullCompletion); QList includeListAccessCompletionItems(const bool& shouldAbort); QList signalSlotAccessCompletionItems(); ///Computes the completion-items for the case that no special kind of access is used(just a list of all suitable items is needed) QList standardAccessCompletionItems(); QList getImplementationHelpers(); QList getImplementationHelpersInternal(const QualifiedIdentifier& minimumScope, DUContext* context); ///If @param forDecl is an instance of a class, find declarations in that class which match @param matchTypes ///@returns the list of matching declarations and whether or not you need the arrow operator (->) to access them QList getLookaheadMatches(Declaration* forDecl, const QList& matchTypes) const; void addLookaheadMatches(const QList items); ///For a given @param container, find members which may potentially be used for lookahead matching ///@param isPointer specifies whether the container should be accessed with operator-> ///@returns a list of declarations paired with whether or not they use "operator->" ///Note that a non-pointer container may declare an operator-> (ie, smart pointer) QList containedDeclarationsForLookahead(Declaration* decl, TopDUContext* top, bool isPointer) const; ///*DUChain must be locked* bool filterDeclaration(Declaration* decl, DUContext* declarationContext = 0, bool dynamic = true) const; ///*DUChain must be locked* bool filterDeclaration(ClassMemberDeclaration* decl, DUContext* declarationContext = 0) const; /// Request a replace of the member-access type at the current cursor position from "oldAccess" /// to "newAccess", for example from "->" to "." /// The actual replacement is delayed into the foreground thread. void replaceCurrentAccess(const QString& oldAccess, const QString& newAccess); ///Creates the group and adds it to m_storedUngroupedItems if items is not empty void eventuallyAddGroup(QString name, int priority, QList< KSharedPtr< KDevelop::CompletionTreeItem > > items); ///@param type The type of the argument the items are matched to. ///*DUChain must be locked* void addSpecialItemsForArgumentType(AbstractType::Ptr type); ///Returns whether the declaration is directly visible from within the current context bool visibleFromWithin(Declaration* decl, DUContext* currentContext) const; ///Returns whether the declaration can be considered an integral constant ///@param acceptHelperItems whether we check for filtering (true) or for marking match quality (false) bool isIntegralConstant(Declaration* decl, bool acceptHelperItems) const; ///Returns whether the end of m_text is a valid completion-position bool isValidPosition(); ///Returns whether this is a valid context for implementation helpers bool isImplementationHelperValid() const; /** * Group adding functions * *DUChain must be locked for these functions* **/ void addOverridableItems(); void addImplementationHelpers(); void addCPPBuiltin(); /** * Specialized completion functions, if these completion types are * valid, no need to continue searching for information about this context * *DUChain must be locked for these functions* **/ ///Handle SIGNAL/SLOT in connect/disconnect, \returns true if valid bool doSignalSlotCompletion(); ///Handle include path completion, \returns true if valid bool doIncludeCompletion(); ///Handle code-completion for constructor-initializers, \returns true if valid bool doConstructorCompletion(); QList namespaceItems(KDevelop::DUContext* duContext, const KDevelop::CursorInRevision& position, bool global, const QSet& skipContexts = QSet()) const; AccessType m_accessType; QString m_expression; QString m_followingText; QString m_operator; //If this completion-context ends with a binary operator, this is the operator ExpressionEvaluationResult m_expressionResult; //Here known argument-expressions and their types, that may have come from sub-contexts, are stored QStringList m_knownArgumentExpressions; QList m_knownArgumentTypes; QString m_functionName; QList m_matchingFunctionOverloads; //If a signal/slot access is performed, and a slot is being connected to a signal, this contains the identifier and the signature Identifier m_connectedSignalIdentifier; QByteArray m_connectedSignalNormalizedSignature; IndexedDeclaration m_connectedSignal; //true if constructor completion is performed bool m_isConstructorCompletion; //include completion items for include completion QList m_includeItems; //0 = No conversion, +1, +2, .. = increase pointer level = &, -1, -2, .. = decrease pointer level = * int m_pointerConversionsBeforeMatching; QList m_storedUngroupedItems; //A specific completion item type to show, or ShowAll, see enum OnlyShow OnlyShow m_onlyShow; //Expression is set to the type part in something like: {type}{varname}{initialization} bool m_expressionIsTypePrefix; bool m_doAccessFiltering; DUContextPointer m_localClass; QList m_cachedMatchTypes; /// Maps container declaration to cached return value of getLookaheadMatches /// This is useful, as otherwise we'd repeat the same stuff for every variable /// with the same type accessible from the current scope mutable QHash > m_lookaheadMatchesCache; friend class ImplementationHelperItem; }; } #endif