diff --git a/language/duchain/declaration.h b/language/duchain/declaration.h index 95b7630c55..c5f245024c 100644 --- a/language/duchain/declaration.h +++ b/language/duchain/declaration.h @@ -1,571 +1,572 @@ /* This file is part of KDevelop Copyright 2006 Hamish Rodda Copyright 2007-2008 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 KDEVPLATFORM_DECLARATION_H #define KDEVPLATFORM_DECLARATION_H #include #include #include "types/abstracttype.h" #include "duchainbase.h" #include "instantiationinformation.h" #include "identifier.h" #include "indexeddeclaration.h" class QByteArray; namespace KDevelop { class AbstractType; class DUContext; class IndexedString; class DeclarationData; class DeclarationId; class Declaration; class IndexedTopDUContext; class TopDUContext; /** * \short Represents a single declaration in a definition-use chain. * * \note A du-context can be freely edited as long as it's parent-context is zero. * In the moment the parent-context is set, the context may only be edited when it * is allowed to edited it's top-level context (@see TopLevelContext::inDUChain()) */ class KDEVPLATFORMLANGUAGE_EXPORT Declaration : public DUChainBase { public: /// Access types enum AccessPolicy { Public /**< a public declaration */, Protected /**< a protected declaration */, Private /**< a private declaration */, DefaultAccess /** TypePtr type() const { return TypePtr::dynamicCast(abstractType()); } /** * Access this declaration's type. * * \note You should not compare or permanently store instances of AbstractType::Ptr. Use IndexedType instead. * \returns this declaration's type, or null if none has been assigned. */ AbstractType::Ptr abstractType() const; /** * Set this declaration's type. * * \param type the type to assign. */ template void setType(TypePtr type) { setAbstractType(AbstractType::Ptr::staticCast(type)); } /** * Set this declaration's \a type. * * \param type this declaration's new type. */ virtual void setAbstractType(AbstractType::Ptr type); /** * Return an indexed form of this declaration's type. * Should be preferred, this is the fastest way, and the correct way for doing equality-comparsion. * * \returns the declaration's type. */ IndexedType indexedType() const; /** * Set this declaration's \a identifier. * * \param identifier this declaration's new identifier */ void setIdentifier(const Identifier& identifier); /** * Access this declaration's \a identifier. * * \returns this declaration's identifier. */ Identifier identifier() const; /** * Access this declaration's \a identifier. * * \return this declaration's identifier in indexed form. This is faster than identifier(), because it * equals the internal representation. Use this for example to do equality-comparison. */ const IndexedIdentifier& indexedIdentifier() const; /** * Determine the global qualified identifier of this declaration. * * \note This function is expensive, equalQualifiedIdentifier() is preferred if you * just want to compare equality. */ QualifiedIdentifier qualifiedIdentifier() const; /** * Compares the qualified identifier of this declaration with the other one, without needing to compute it. * This is more efficient than comparing the results of qualifiedIdentifier(). * * \param rhs declaration to compare identifiers with * \returns true if the identifiers are equal, otherwise false. */ bool equalQualifiedIdentifier(const Declaration* rhs) const; /** * Returns the kind of this declaration. @see Kind */ Kind kind() const; /** * Set the kind. * * \param kind new kind */ void setKind(Kind kind); /** * Returns the comment associated to this declaration in the source-code, * or an invalid string if there is none. * * Stored in utf-8 encoding. */ QByteArray comment() const; /** * Sets the comment for this declaration. * * @note Should be utf-8 encoded. */ void setComment(const QByteArray& str); /** * Sets the comment for this declaration. */ void setComment(const QString& str); /** * Access whether this declaration is in the symbol table. * * \returns true if this declaration is in the symbol table, otherwise false. */ bool inSymbolTable() const; /** * Adds or removes this declaration to/from the symbol table. * * \param inSymbolTable true to add this declaration to the symbol table, false to remove it. */ virtual void setInSymbolTable(bool inSymbolTable); /** * Equivalence operator. * * \param other Other declaration to compare. * \returns true if the declarations are equal, otherwise false. */ bool operator==(const Declaration& other) const; /** * Determine this declaration as a string. \returns this declaration as a string. */ virtual QString toString() const; /** * Returns a map of files to use-ranges. * * The key of the returned map is an url of a file. The value * is a list with all use-ranges of this declaration in that file. * * \note The ranges are in the documents local revision, * use \c DUChainUtils::transformFromRevision or \c usesCurrentRevision() * * \note The uses are unique, no 2 uses are returend that have the same range within the same file. * * \note This is a non-trivial operation and hence expensive. */ QMap > uses() const; /** * Determines whether the declaration has any uses or not. * * Cheaper than calling uses(). */ bool hasUses() const; /** * Returns a map of files to use-ranges. * * The key of the returned map is an url of a file. The value * is a list with all use-ranges of this declaration in that file. * * \note The uses are unique, no 2 uses are returend that have the same range within the same file. * * \warning This must be called only from within the foreground, or with the foreground lock locked. * * \note This is a non-trivial operation and hence expensive. */ QMap > usesCurrentRevision() const; /** * This hash-value should differentiate between multiple different * declarations that have the same qualifiedIdentifier, but should have a different * identity, and thus own Definitions and own Uses assigned. * * Affected by function-arguments, whether this is a template-declaration, etc.. */ virtual uint additionalIdentity() const; /** * TODO document * */ virtual IndexedInstantiationInformation specialization() const; /** * \see DeclarationId * * \param forceDirect When this is true, the DeclarationId is force to be direct, * and can be resolved without a symbol-table and top-context. * The same goes for Declarations that have \c alwaysForceDirect() * set to true. */ virtual DeclarationId id(bool forceDirect = false) const; /** * Returns an index that uniquely identifies this declaration within its surrounding top-context. * * That index can be passed to \c TopDUContext::declarationFromIndex(index) to get the declaration. * This is only valid when the declaration is not a specialization (\c specialization() returns 0), * and if it is not anonymous in its context. * * \note for this to be valid, allocateOwnIndex() must have been called first. * \note the highest big of the index is always zero! * \returns the index of the declaration within its TopDUContext. */ uint ownIndex() const; /** * Whether this declaration has been inserted anonymously into its parent-context */ bool isAnonymous() const; /** * Clear the index for this declaration in the top context that was allocated with allocateOwnIndex(). */ void clearOwnIndex(); /** * Create an index to this declaration from the topContext(). Needed to be able to retrieve ownIndex(). */ void allocateOwnIndex(); /** * Returns a clone of this declaration, with the difference that the returned declaration * has no context set, i.e. \c context() returns zero. * * The declaration will not be registered anywhere, so you must care about its deletion. * * This declaration's text-range will be referenced from the clone, so the clone must not * live longer than the original. */ Declaration* clone() const; /** * Signalized that among multiple possible specializations, this one should be used in the UI from now on. * * Currently mainly used in C++ for template support. The default-implementation registers the current * specialization of this declaration to SpecializationStore if it is nonzero. */ virtual void activateSpecialization(); enum { Identity = 7 }; protected: /** * Constructor for copy constructors in subclasses. * * \param dd data to copy. * \param url document url in which this object is located. * \param range text range which this object covers. */ Declaration( DeclarationData & dd, const RangeInRevision& range ); /** * Returns true if this declaration is being currently destroyed persistently, * which means that it should eventually deregister itself from persistent storage facilities. * * Only call this from destructors. */ bool persistentlyDestroying() const; DUCHAIN_DECLARE_DATA(Declaration) private: /** * Sub-classes should implement this and should copy as much information into the clone as possible without breaking the du-chain. * Sub-classes should also implement a public copy-constructor that can be used for cloning by sub-classes. * * \note You do not have to implement this for your language if you are not going to use it(the du-chain itself does not and should not depend on it). * */ virtual Declaration* clonePrivate() const; void updateCodeModel(); void rebuildDynamicData(DUContext* parent, uint ownIndex) override; friend class DUContext; friend class IndexedDeclaration; friend class LocalIndexedDeclaration; friend class TopDUContextDynamicData; DUContext* m_context; TopDUContext* m_topContext; int m_indexInTopContext; }; } #endif // KDEVPLATFORM_DECLARATION_H diff --git a/tests/json/jsondeclarationtests.h b/tests/json/jsondeclarationtests.h index 3ae82c0b0e..c858ec0166 100644 --- a/tests/json/jsondeclarationtests.h +++ b/tests/json/jsondeclarationtests.h @@ -1,331 +1,334 @@ /* This file is part of KDevelop Copyright 2012 Olivier de Gaalon 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_JSONDECLARATIONTESTS_H #define KDEVPLATFORM_JSONDECLARATIONTESTS_H #include "language/duchain/ducontext.h" #include "language/duchain/declaration.h" #include "language/duchain/indexeddeclaration.h" #include "language/duchain/identifier.h" #include "language/duchain/abstractfunctiondeclaration.h" #include "language/duchain/types/typeutils.h" #include "language/duchain/types/identifiedtype.h" #include #include "language/duchain/duchain.h" #include "language/duchain/functiondefinition.h" #include "language/duchain/definitions.h" #include #include "jsontesthelpers.h" /** * JSON Object Specification: * DeclTestObject: Mapping of (string) declaration test names to values * TypeTestObject: Mapping of (string) type test names to values * CtxtTestObject: Mapping of (string) context test names to values * * Quick Reference: * useCount : int * useRanges : string array * identifier : string * qualifiedIdentifier : string * internalContext : CtxtTestObject * internalFunctionContext : CtxtTestObject * type : TypeTestObject * unaliasedType : TypeTestObject * targetType : TypeTestObject * returnType : TypeTestObject * isAbstract : bool * isVirtual : bool * isStatic : bool * declaration : DeclTestObject * definition : DeclTestObject * identifiedTypeDeclaration : DeclTestObject * null : bool * defaultParameter : string * toString : string * range : string * kind : string * isDeprecated : bool * isDefinition : bool */ namespace KDevelop { template<> QString TestSuite::objectInformation(Declaration *decl) { VERIFY_NOT_NULL(decl); return QStringLiteral("(Declaration on line %1 in %2)") .arg(decl->range().start.line + 1) .arg(decl->topContext()->url().str()); } namespace DeclarationTests { using namespace JsonTestHelpers; ///JSON type: int ///@returns whether the declaration's number of uses matches the given value DeclarationTest(useCount) { int uses = 0; foreach(const QList& useRanges, decl->uses()) { uses += useRanges.size(); } return compareValues(uses, value, "Declaration's use count "); } ///JSON type: string array ///@returns whether the declaration's ranges match the given value DeclarationTest(useRanges) { QStringList ranges; foreach(const QList& useRanges, decl->uses()) { foreach(const RangeInRevision &range, useRanges) { ranges << rangeStr(range); } } const QStringList testValues = value.toStringList(); return ranges == testValues ? SUCCESS : QStringLiteral("Declaration's use ranges (\"%1\") don't match test data (\"%2\").").arg(ranges.join(", ")).arg(testValues.join(", ")); } ///JSON type: string ///@returns whether the declaration's identifier matches the given value DeclarationTest(identifier) { VERIFY_NOT_NULL(decl); return compareValues(decl->identifier().toString(), value, "Declaration's identifier"); } ///JSON type: string ///@returns whether the declaration's qualified identifier matches the given value DeclarationTest(qualifiedIdentifier) { VERIFY_NOT_NULL(decl); return compareValues(decl->qualifiedIdentifier().toString(), value, "Declaration's qualified identifier"); } ///JSON type: CtxtTestObject ///@returns whether the tests for the declaration's internal context pass DeclarationTest(internalContext) { VERIFY_NOT_NULL(decl); return testObject(decl->internalContext(), value, "Declaration's internal context"); } ///JSON type: CtxtTestObject ///@returns whether the tests for the declaration's internal function context pass DeclarationTest(internalFunctionContext) { const QString NO_INTERNAL_CTXT = "%1 has no internal function context."; AbstractFunctionDeclaration *absFuncDecl = dynamic_cast(decl); if (!absFuncDecl || !absFuncDecl->internalFunctionContext()) return NO_INTERNAL_CTXT.arg(decl->qualifiedIdentifier().toString()); return testObject(absFuncDecl->internalFunctionContext(), value, "Declaration's internal function context"); } /*FIXME: The type functions need some renaming and moving around * Some (all?) functions from cpp's TypeUtils should be moved to the kdevplatform type utils * targetType is exactly like realType except it also tosses pointers * shortenTypeForViewing should go to type utils (and it's broken, it places const to the left of all *'s when it should be left or right of the type) * UnaliasedType seems to be unable to understand aliases involving templates, perhaps a cpp version is in order */ ///JSON type: TypeTestObject ///@returns whether the tests for the declaration's type pass DeclarationTest(type) { VERIFY_NOT_NULL(decl); return testObject(decl->abstractType(), value, "Declaration's type"); } ///JSON type: TypeTestObject ///@returns whether the tests for the declaration's unaliased type pass (TypeUtils::unaliasedType) DeclarationTest(unaliasedType) { VERIFY_NOT_NULL(decl); return testObject(TypeUtils::unAliasedType(decl->abstractType()), value, "Declaration's unaliased type"); } ///JSON type: TypeTestObject ///@returns whether the tests for the declaration's target type pass (TypeUtils::targetType) DeclarationTest(targetType) { VERIFY_NOT_NULL(decl); return testObject(TypeUtils::targetType(decl->abstractType(), decl->topContext()), value, "Declaration's target type"); } ///JSON type: TestTypeObject ///@returns the DeclarationTest(returnType) { FunctionType::Ptr functionType = decl->abstractType().cast(); AbstractType::Ptr returnType; if (functionType) { returnType = functionType->returnType(); } return testObject(returnType, value, "Declaration's return type"); } ///JSON type: DeclTestObject ///@returns The IdentifiedType's declaration DeclarationTest(identifiedTypeDeclaration) { const QString UN_ID_ERROR = "Unable to identify declaration of type \"%1\"."; AbstractType::Ptr type = TypeUtils::targetType(decl->abstractType(), decl->topContext()); IdentifiedType* idType = dynamic_cast(type.data()); Declaration* idDecl = idType ? idType->declaration(decl->topContext()) : 0; if (!idDecl) return UN_ID_ERROR.arg(type->toString()); return testObject(idDecl, value, "IdentifiedType's declaration"); } ///JSON type: bool ///@returns whether the (function) declaration's isVirtual matches the given value DeclarationTest(isVirtual) { const QString NOT_A_FUNCTION = "Non-function declaration cannot be virtual."; AbstractFunctionDeclaration *absFuncDecl = dynamic_cast(decl); if (!absFuncDecl) return NOT_A_FUNCTION; return compareValues(absFuncDecl->isVirtual(), value, "Declaration's isVirtual"); } ///JSON type: bool ///@returns whether the (function) declaration's isAbstract matches the given value DeclarationTest(isAbstract) { const QString NOT_A_FUNCTION = "Non-class-member declaration cannot be abstract."; auto *absFuncDecl = dynamic_cast(decl); if (!absFuncDecl) return NOT_A_FUNCTION; return compareValues(absFuncDecl->isAbstract(), value, "Declaration's isAbstract"); } ///JSON type: bool ///@returns whether the (class-member) declaration's isStatic matches the given value DeclarationTest(isStatic) { const QString NOT_A_MEMBER = "Non-class-member declaration cannot be static."; auto memberDecl = dynamic_cast(decl); if (!memberDecl) return NOT_A_MEMBER; return compareValues(memberDecl->isStatic(), value, "Declaration's isStatic"); } ///JSON type: DeclTestObject ///@returns whether the tests for the function declaration's definition pass DeclarationTest(definition) { KDevVarLengthArray definitions = DUChain::definitions()->definitions(decl->id()); Declaration *declDef = 0; if (definitions.size()) declDef = definitions.at(0).declaration(); return testObject(declDef, value, "Declaration's definition"); } ///JSON type: DeclTestObject ///@returns whether the tests for the function definition's declaration pass DeclarationTest(declaration) { FunctionDefinition *def = dynamic_cast(decl); Declaration *defDecl = nullptr; if (def) defDecl = def->declaration(decl->topContext()); return testObject(defDecl, value, "Definition's declaration"); } ///JSON type: bool ///@returns whether the declaration's nullity matches the given value DeclarationTest(null) { return compareValues(decl == 0, value, "Declaration's nullity"); } ///JSON type: bool ///@returns whether the declaration's default parameter matches the given value DeclarationTest(defaultParameter) { const QString NOT_IN_FUNC_CTXT = "Asked for a default parameter for a declaration outside of a function context."; const QString OWNER_NOT_FUNC = "Function context not owned by function declaration (what on earth did you do?)."; DUContext *context = decl->context(); if (!context || context->type() != DUContext::Function) return NOT_IN_FUNC_CTXT; AbstractFunctionDeclaration *funcDecl = dynamic_cast(context->owner()); if (!funcDecl) return OWNER_NOT_FUNC; int argIndex = context->localDeclarations().indexOf(decl); return compareValues(funcDecl->defaultParameterForArgument(argIndex).str(), value, "Declaration's default parameter"); } ///JSON type: string ///@returns stringified declaration DeclarationTest(toString) { VERIFY_NOT_NULL(decl); return compareValues(decl->toString(), value, "Declaration's toString"); } ///JSON type: string ///@returns stringified declaration range DeclarationTest(range) { VERIFY_NOT_NULL(decl); return compareValues(rangeStr(decl->range()), value, "Declaration's range"); } ///JSON type: string ///@returns stringified declaration kind DeclarationTest(kind) { VERIFY_NOT_NULL(decl); QString kind; switch (decl->kind()) { case KDevelop::Declaration::Alias: kind = "Alias"; break; case KDevelop::Declaration::Import: kind = "Import"; break; case KDevelop::Declaration::Instance: kind = "Instance"; break; case KDevelop::Declaration::Namespace: kind = "Namespace"; break; case KDevelop::Declaration::NamespaceAlias: kind = "NamespaceAlias"; break; case KDevelop::Declaration::Type: kind = "Type"; break; + case KDevelop::Declaration::Macro: + kind = "Macro"; + break; } return compareValues(kind, value, "Declaration's kind"); } ///JSON type: bool ///@returns whether the declaration's isDeprecated matches the given value DeclarationTest(isDeprecated) { VERIFY_NOT_NULL(decl); return compareValues(decl->isDeprecated(), value, "Declaration's isDeprecated"); } ///JSON type: bool ///@returns whether the declaration's isDefinition matches the given value DeclarationTest(isDefinition) { VERIFY_NOT_NULL(decl); return compareValues(decl->isDefinition(), value, "Declaration's isDefinition"); } } } #endif //KDEVPLATFORM_JSONDECLARATIONTESTS_H