/* 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_CODEGENERATOR_H #define KDEVPLATFORM_CODEGENERATOR_H #include "language/editor/documentrange.h" #include "../duchain/indexedstring.h" #include "../duchain/topducontext.h" #include "../duchain/duchain.h" #include "language/interfaces/iastcontainer.h" namespace KDevelop { template class AstChangeSet; class DUContext; class DUChainChangeSet; class DocumentChangeSet; /** * \short Base class for generic code generators * * CodeGeneratorBase provides an api for a step-by-step process to * create and/or refactor code. * * This class should be used as a superclass only when du-chain level * changes are made, since this level knows nothing about the * language-specific AST. For more complex changes that require knowledge * about the language AST, use CodeGenerator * * \see Refactoring * \see CodeGenerator * \author Hamish Rodda */ class KDEVPLATFORMLANGUAGE_EXPORT CodeGeneratorBase { public: CodeGeneratorBase(); virtual ~CodeGeneratorBase(); enum State { Precondition, UserInput, Processing, Review, Finished }; /** * Check whether the preconditions of this generation are met at the given \a context and * \a position. * \returns true if conditions are met and the generator can progress, otherwise false if * the conditions are not met. Use setErrorText to specify the nature of the Error. */ virtual bool checkPreconditions(DUContext* context, const DocumentRange& position) = 0; /** * Gather information required from the user for this generator. * * \returns true if all of the information is retrieved, otherwise false, Use setErrorText * to specify the nature of the Error. */ virtual bool gatherInformation() = 0; /** * Do final condition checking and perform the code generation. * * \returns true if code generation was successful, false otherwise. Use setErrorText to * specify the nature of the Error. */ virtual bool process() = 0; const QString & errorText() const; // Implementation from kJob bool execute(); /** * @brief Indicates that this generation should not expect interaction with the user/ * Most probable scenarios are: Testing, and a generator that is being used by another one * @param context If not NULL, the custom context to use, instead of user selection * @param position If not NULL, the cursom range to use instead of user selection * @note If this function is called, then gather information will not be called. * Derived classes should provide an alternative way of setting up the generator. */ void autoGenerate(DUContext * context, const DocumentRange * range); /** * \return The Document Change set to add a single Change, it is more addicient than creating a local DocumentChangeSet and merging it */ DocumentChangeSet & documentChangeSet(); protected: /** * Generate text edits from duchain change set. * This generator now owns the changeset, and will delete it. * * You may call this method multiple times to edit different files. */ void addChangeSet(DUChainChangeSet* duChainChange); void addChangeSet(DocumentChangeSet & docChangeSet); /** * Accessor for KJob's KJob::setErrorText. */ void setErrorText(const QString & error); /** * Inform the derived class if this generation is being performed without user interaction */ bool autoGeneration() const; /** * Clean up all the change sets that this generator is in charge of */ void clearChangeSets(); private: class CodeGeneratorPrivate * const d; bool displayChanges(); }; /** * \brief Base class for Ast aware code generators * * This class provides convenience for adding AstChangeSet, storing * the IAstContainer from the TopDUContext, and in general managing * Code generators that manipulate the AST * * \see CodeGeneratorBase * \author Ramón Zarazúa */ template class CodeGenerator : public CodeGeneratorBase { public: ~CodeGenerator() { clearChangeSets(); } protected: /// Convenience definition of the TopAstNode that is contained by this AstContainer typedef typename AstContainer::TopAstNode TopAstNode; typedef AstChangeSet LanguageChangeSet; /** * Query an AST of a particular file */ TopAstNode * ast(const IndexedString & file) { return astContainer(file)->topAstNode(); } TopAstNode * ast(const TopDUContext & context) { return astContainer(context)->topAstNode(); } typename AstContainer::Ptr astContainer(const IndexedString & file) { if(!m_AstContainers.contains(file)) { kDebug() << "Ast requested for: " << file.str(); TopDUContext * context = DUChain::self()->waitForUpdate(file, KDevelop::TopDUContext::AST).data(); Q_ASSERT(context); m_AstContainers[file] = AstContainer::Ptr::template staticCast( context->ast() ); } return m_AstContainers[file]; } typename AstContainer::Ptr astContainer(const TopDUContext & context) { return astContainer(context.url()); } /** * Generate text edits from duchain / ast change set. * * You may call this method multiple times to edit different files. */ void addChangeSet(DUChainChangeSet * duChainChange) { CodeGeneratorBase::addChangeSet(duChainChange); } void addChangeSet(DocumentChangeSet & doc) { CodeGeneratorBase::addChangeSet(doc); } /** * Generate text edits from duchain / ast change set. * * You may call this method multiple times to edit different files. */ void addChangeSet(LanguageChangeSet * astChange); void clearChangeSets() { CodeGeneratorBase::clearChangeSets(); } /** * Inform the derived class if this generation is being performed without user interaction */ bool autoGeneration() const { return CodeGeneratorBase::autoGeneration(); } /** * Accessor for KJob's KJob::setErrorText. */ void setErrorText(const QString & error) { CodeGeneratorBase::setErrorText(error); } private: typedef QMap AstContainerMap; AstContainerMap m_AstContainers; }; } #endif // KDEVPLATFORM_CODEGENERATOR_H