forked from qt-creator/qt-creator
		
	C++: added quickfix to insert a method definition.
Reviewed-by: Christian Kamm
This commit is contained in:
		
							
								
								
									
										217
									
								
								src/plugins/cpptools/cpprefactoringchanges.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								src/plugins/cpptools/cpprefactoringchanges.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,217 @@
 | 
			
		||||
/**************************************************************************
 | 
			
		||||
**
 | 
			
		||||
** This file is part of Qt Creator
 | 
			
		||||
**
 | 
			
		||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
 | 
			
		||||
**
 | 
			
		||||
** Contact: Nokia Corporation (qt-info@nokia.com)
 | 
			
		||||
**
 | 
			
		||||
** Commercial Usage
 | 
			
		||||
**
 | 
			
		||||
** Licensees holding valid Qt Commercial licenses may use this file in
 | 
			
		||||
** accordance with the Qt Commercial License Agreement provided with the
 | 
			
		||||
** Software or, alternatively, in accordance with the terms contained in
 | 
			
		||||
** a written agreement between you and Nokia.
 | 
			
		||||
**
 | 
			
		||||
** GNU Lesser General Public License Usage
 | 
			
		||||
**
 | 
			
		||||
** Alternatively, this file may be used under the terms of the GNU Lesser
 | 
			
		||||
** General Public License version 2.1 as published by the Free Software
 | 
			
		||||
** Foundation and appearing in the file LICENSE.LGPL included in the
 | 
			
		||||
** packaging of this file.  Please review the following information to
 | 
			
		||||
** ensure the GNU Lesser General Public License version 2.1 requirements
 | 
			
		||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 | 
			
		||||
**
 | 
			
		||||
** If you are unsure which license is appropriate for your use, please
 | 
			
		||||
** contact the sales department at http://qt.nokia.com/contact.
 | 
			
		||||
**
 | 
			
		||||
**************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "cpprefactoringchanges.h"
 | 
			
		||||
 | 
			
		||||
#include <TranslationUnit.h>
 | 
			
		||||
#include <AST.h>
 | 
			
		||||
#include <cpptools/cppcodeformatter.h>
 | 
			
		||||
#include <texteditor/texteditorsettings.h>
 | 
			
		||||
#include <texteditor/tabsettings.h>
 | 
			
		||||
 | 
			
		||||
#include <QtGui/QTextBlock>
 | 
			
		||||
 | 
			
		||||
using namespace CPlusPlus;
 | 
			
		||||
using namespace CppTools;
 | 
			
		||||
using namespace Utils;
 | 
			
		||||
 | 
			
		||||
CppRefactoringChanges::CppRefactoringChanges(const Snapshot &snapshot)
 | 
			
		||||
    : m_snapshot(snapshot)
 | 
			
		||||
    , m_modelManager(CppTools::CppModelManagerInterface::instance())
 | 
			
		||||
{
 | 
			
		||||
    Q_ASSERT(m_modelManager);
 | 
			
		||||
    m_workingCopy = m_modelManager->workingCopy();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Snapshot &CppRefactoringChanges::snapshot() const
 | 
			
		||||
{
 | 
			
		||||
    return m_snapshot;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CppRefactoringFile CppRefactoringChanges::file(const QString &fileName)
 | 
			
		||||
{
 | 
			
		||||
    return CppRefactoringFile(fileName, this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CppRefactoringChanges::indentSelection(const QTextCursor &selection) const
 | 
			
		||||
{
 | 
			
		||||
    // ### shares code with CPPEditor::indent()
 | 
			
		||||
    QTextDocument *doc = selection.document();
 | 
			
		||||
 | 
			
		||||
    QTextBlock block = doc->findBlock(selection.selectionStart());
 | 
			
		||||
    const QTextBlock end = doc->findBlock(selection.selectionEnd()).next();
 | 
			
		||||
 | 
			
		||||
    const TextEditor::TabSettings &tabSettings(TextEditor::TextEditorSettings::instance()->tabSettings());
 | 
			
		||||
    CppTools::QtStyleCodeFormatter codeFormatter(tabSettings);
 | 
			
		||||
    codeFormatter.updateStateUntil(block);
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        int indent;
 | 
			
		||||
        int padding;
 | 
			
		||||
        codeFormatter.indentFor(block, &indent, &padding);
 | 
			
		||||
        tabSettings.indentLine(block, indent + padding, padding);
 | 
			
		||||
        codeFormatter.updateLineStateChange(block);
 | 
			
		||||
        block = block.next();
 | 
			
		||||
    } while (block.isValid() && block != end);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CppRefactoringChanges::fileChanged(const QString &fileName)
 | 
			
		||||
{
 | 
			
		||||
    m_modelManager->updateSourceFiles(QStringList(fileName));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
CppRefactoringFile::CppRefactoringFile()
 | 
			
		||||
{ }
 | 
			
		||||
 | 
			
		||||
CppRefactoringFile::CppRefactoringFile(const QString &fileName, CppRefactoringChanges *refactoringChanges)
 | 
			
		||||
    : RefactoringFile(fileName, refactoringChanges)
 | 
			
		||||
{ }
 | 
			
		||||
 | 
			
		||||
CppRefactoringFile::CppRefactoringFile(TextEditor::BaseTextEditor *editor, CPlusPlus::Document::Ptr document)
 | 
			
		||||
    : RefactoringFile()
 | 
			
		||||
    , m_cppDocument(document)
 | 
			
		||||
{
 | 
			
		||||
    m_fileName = document->fileName();
 | 
			
		||||
    m_editor = editor;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Document::Ptr CppRefactoringFile::cppDocument() const
 | 
			
		||||
{
 | 
			
		||||
    if (!m_cppDocument) {
 | 
			
		||||
        const QString source = document()->toPlainText();
 | 
			
		||||
        const QString name = fileName();
 | 
			
		||||
        const Snapshot &snapshot = refactoringChanges()->snapshot();
 | 
			
		||||
 | 
			
		||||
        const QByteArray contents = snapshot.preprocessedCode(source, name);
 | 
			
		||||
        m_cppDocument = snapshot.documentFromSource(contents, name);
 | 
			
		||||
        m_cppDocument->check();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return m_cppDocument;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Scope *CppRefactoringFile::scopeAt(unsigned index) const
 | 
			
		||||
{
 | 
			
		||||
    unsigned line, column;
 | 
			
		||||
    cppDocument()->translationUnit()->getTokenStartPosition(index, &line, &column);
 | 
			
		||||
    return cppDocument()->scopeAt(line, column);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CppRefactoringFile::isCursorOn(unsigned tokenIndex) const
 | 
			
		||||
{
 | 
			
		||||
    QTextCursor tc = cursor();
 | 
			
		||||
    int cursorBegin = tc.selectionStart();
 | 
			
		||||
 | 
			
		||||
    int start = startOf(tokenIndex);
 | 
			
		||||
    int end = endOf(tokenIndex);
 | 
			
		||||
 | 
			
		||||
    if (cursorBegin >= start && cursorBegin <= end)
 | 
			
		||||
        return true;
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CppRefactoringFile::isCursorOn(const AST *ast) const
 | 
			
		||||
{
 | 
			
		||||
    QTextCursor tc = cursor();
 | 
			
		||||
    int cursorBegin = tc.selectionStart();
 | 
			
		||||
 | 
			
		||||
    int start = startOf(ast);
 | 
			
		||||
    int end = endOf(ast);
 | 
			
		||||
 | 
			
		||||
    if (cursorBegin >= start && cursorBegin <= end)
 | 
			
		||||
        return true;
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ChangeSet::Range CppRefactoringFile::range(unsigned tokenIndex) const
 | 
			
		||||
{
 | 
			
		||||
    const Token &token = tokenAt(tokenIndex);
 | 
			
		||||
    unsigned line, column;
 | 
			
		||||
    cppDocument()->translationUnit()->getPosition(token.begin(), &line, &column);
 | 
			
		||||
    const int start = document()->findBlockByNumber(line - 1).position() + column - 1;
 | 
			
		||||
    return ChangeSet::Range(start, start + token.length());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ChangeSet::Range CppRefactoringFile::range(AST *ast) const
 | 
			
		||||
{
 | 
			
		||||
    return ChangeSet::Range(startOf(ast), endOf(ast));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int CppRefactoringFile::startOf(unsigned index) const
 | 
			
		||||
{
 | 
			
		||||
    unsigned line, column;
 | 
			
		||||
    cppDocument()->translationUnit()->getPosition(tokenAt(index).begin(), &line, &column);
 | 
			
		||||
    return document()->findBlockByNumber(line - 1).position() + column - 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int CppRefactoringFile::startOf(const AST *ast) const
 | 
			
		||||
{
 | 
			
		||||
    return startOf(ast->firstToken());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int CppRefactoringFile::endOf(unsigned index) const
 | 
			
		||||
{
 | 
			
		||||
    unsigned line, column;
 | 
			
		||||
    cppDocument()->translationUnit()->getPosition(tokenAt(index).end(), &line, &column);
 | 
			
		||||
    return document()->findBlockByNumber(line - 1).position() + column - 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int CppRefactoringFile::endOf(const AST *ast) const
 | 
			
		||||
{
 | 
			
		||||
    unsigned end = ast->lastToken();
 | 
			
		||||
    Q_ASSERT(end > 0);
 | 
			
		||||
    return endOf(end - 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CppRefactoringFile::startAndEndOf(unsigned index, int *start, int *end) const
 | 
			
		||||
{
 | 
			
		||||
    unsigned line, column;
 | 
			
		||||
    Token token(tokenAt(index));
 | 
			
		||||
    cppDocument()->translationUnit()->getPosition(token.begin(), &line, &column);
 | 
			
		||||
    *start = document()->findBlockByNumber(line - 1).position() + column - 1;
 | 
			
		||||
    *end = *start + token.length();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QString CppRefactoringFile::textOf(const AST *ast) const
 | 
			
		||||
{
 | 
			
		||||
    return textOf(startOf(ast), endOf(ast));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Token &CppRefactoringFile::tokenAt(unsigned index) const
 | 
			
		||||
{
 | 
			
		||||
    return cppDocument()->translationUnit()->tokenAt(index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CppRefactoringChanges *CppRefactoringFile::refactoringChanges() const
 | 
			
		||||
{
 | 
			
		||||
    return static_cast<CppRefactoringChanges *>(m_refactoringChanges);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										104
									
								
								src/plugins/cpptools/cpprefactoringchanges.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/plugins/cpptools/cpprefactoringchanges.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
/**************************************************************************
 | 
			
		||||
**
 | 
			
		||||
** This file is part of Qt Creator
 | 
			
		||||
**
 | 
			
		||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
 | 
			
		||||
**
 | 
			
		||||
** Contact: Nokia Corporation (qt-info@nokia.com)
 | 
			
		||||
**
 | 
			
		||||
** Commercial Usage
 | 
			
		||||
**
 | 
			
		||||
** Licensees holding valid Qt Commercial licenses may use this file in
 | 
			
		||||
** accordance with the Qt Commercial License Agreement provided with the
 | 
			
		||||
** Software or, alternatively, in accordance with the terms contained in
 | 
			
		||||
** a written agreement between you and Nokia.
 | 
			
		||||
**
 | 
			
		||||
** GNU Lesser General Public License Usage
 | 
			
		||||
**
 | 
			
		||||
** Alternatively, this file may be used under the terms of the GNU Lesser
 | 
			
		||||
** General Public License version 2.1 as published by the Free Software
 | 
			
		||||
** Foundation and appearing in the file LICENSE.LGPL included in the
 | 
			
		||||
** packaging of this file.  Please review the following information to
 | 
			
		||||
** ensure the GNU Lesser General Public License version 2.1 requirements
 | 
			
		||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 | 
			
		||||
**
 | 
			
		||||
** If you are unsure which license is appropriate for your use, please
 | 
			
		||||
** contact the sales department at http://qt.nokia.com/contact.
 | 
			
		||||
**
 | 
			
		||||
**************************************************************************/
 | 
			
		||||
 | 
			
		||||
#ifndef CPPREFACTORINGCHANGES_H
 | 
			
		||||
#define CPPREFACTORINGCHANGES_H
 | 
			
		||||
 | 
			
		||||
#include <ASTfwd.h>
 | 
			
		||||
#include <cplusplus/CppDocument.h>
 | 
			
		||||
#include <cplusplus/LookupContext.h>
 | 
			
		||||
 | 
			
		||||
#include <cpptools/cppmodelmanagerinterface.h>
 | 
			
		||||
#include <cpptools/cpptools_global.h>
 | 
			
		||||
 | 
			
		||||
#include <texteditor/refactoringchanges.h>
 | 
			
		||||
 | 
			
		||||
namespace CppTools {
 | 
			
		||||
 | 
			
		||||
class CppRefactoringChanges;
 | 
			
		||||
 | 
			
		||||
class CPPTOOLS_EXPORT CppRefactoringFile: public TextEditor::RefactoringFile
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    CppRefactoringFile();
 | 
			
		||||
    CppRefactoringFile(const QString &fileName, CppRefactoringChanges *refactoringChanges);
 | 
			
		||||
    CppRefactoringFile(TextEditor::BaseTextEditor *editor, CPlusPlus::Document::Ptr document);
 | 
			
		||||
 | 
			
		||||
    CPlusPlus::Document::Ptr cppDocument() const;
 | 
			
		||||
 | 
			
		||||
    CPlusPlus::Scope *scopeAt(unsigned index) const;
 | 
			
		||||
 | 
			
		||||
    bool isCursorOn(unsigned tokenIndex) const;
 | 
			
		||||
    bool isCursorOn(const CPlusPlus::AST *ast) const;
 | 
			
		||||
 | 
			
		||||
    Range range(int start, int end) const;
 | 
			
		||||
    Range range(unsigned tokenIndex) const;
 | 
			
		||||
    Range range(CPlusPlus::AST *ast) const;
 | 
			
		||||
 | 
			
		||||
    const CPlusPlus::Token &tokenAt(unsigned index) const;
 | 
			
		||||
 | 
			
		||||
    int startOf(unsigned index) const;
 | 
			
		||||
    int startOf(const CPlusPlus::AST *ast) const;
 | 
			
		||||
    int endOf(unsigned index) const;
 | 
			
		||||
    int endOf(const CPlusPlus::AST *ast) const;
 | 
			
		||||
 | 
			
		||||
    void startAndEndOf(unsigned index, int *start, int *end) const;
 | 
			
		||||
 | 
			
		||||
    using TextEditor::RefactoringFile::textOf;
 | 
			
		||||
    QString textOf(const CPlusPlus::AST *ast) const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    CppRefactoringChanges *refactoringChanges() const;
 | 
			
		||||
 | 
			
		||||
    mutable CPlusPlus::Document::Ptr m_cppDocument;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class CPPTOOLS_EXPORT CppRefactoringChanges: public TextEditor::RefactoringChanges
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    CppRefactoringChanges(const CPlusPlus::Snapshot &snapshot);
 | 
			
		||||
 | 
			
		||||
    const CPlusPlus::Snapshot &snapshot() const;
 | 
			
		||||
    CppRefactoringFile file(const QString &fileName);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    virtual void indentSelection(const QTextCursor &selection) const;
 | 
			
		||||
    virtual void fileChanged(const QString &fileName);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    CPlusPlus::Document::Ptr m_thisDocument;
 | 
			
		||||
    CPlusPlus::Snapshot m_snapshot;
 | 
			
		||||
    CPlusPlus::LookupContext m_context;
 | 
			
		||||
    CppTools::CppModelManagerInterface *m_modelManager;
 | 
			
		||||
    CppTools::CppModelManagerInterface::WorkingCopy m_workingCopy;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace CppTools
 | 
			
		||||
 | 
			
		||||
#endif // CPPREFACTORINGCHANGES_H
 | 
			
		||||
@@ -25,7 +25,9 @@ HEADERS += completionsettingspage.h \
 | 
			
		||||
    cppfilesettingspage.h \
 | 
			
		||||
    cppfindreferences.h \
 | 
			
		||||
    cppcodeformatter.h \
 | 
			
		||||
    symbolsfindfilter.h
 | 
			
		||||
    symbolsfindfilter.h \
 | 
			
		||||
    insertionpointlocator.h \
 | 
			
		||||
    cpprefactoringchanges.h
 | 
			
		||||
 | 
			
		||||
SOURCES += completionsettingspage.cpp \
 | 
			
		||||
    cppclassesfilter.cpp \
 | 
			
		||||
@@ -42,7 +44,9 @@ SOURCES += completionsettingspage.cpp \
 | 
			
		||||
    abstracteditorsupport.cpp \
 | 
			
		||||
    cppfindreferences.cpp \
 | 
			
		||||
    cppcodeformatter.cpp \
 | 
			
		||||
    symbolsfindfilter.cpp
 | 
			
		||||
    symbolsfindfilter.cpp \
 | 
			
		||||
    insertionpointlocator.cpp \
 | 
			
		||||
    cpprefactoringchanges.cpp
 | 
			
		||||
 | 
			
		||||
FORMS += completionsettingspage.ui \
 | 
			
		||||
    cppfilesettingspage.ui
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										329
									
								
								src/plugins/cpptools/insertionpointlocator.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										329
									
								
								src/plugins/cpptools/insertionpointlocator.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,329 @@
 | 
			
		||||
/**************************************************************************
 | 
			
		||||
**
 | 
			
		||||
** This file is part of Qt Creator
 | 
			
		||||
**
 | 
			
		||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
 | 
			
		||||
**
 | 
			
		||||
** Contact: Nokia Corporation (qt-info@nokia.com)
 | 
			
		||||
**
 | 
			
		||||
** Commercial Usage
 | 
			
		||||
**
 | 
			
		||||
** Licensees holding valid Qt Commercial licenses may use this file in
 | 
			
		||||
** accordance with the Qt Commercial License Agreement provided with the
 | 
			
		||||
** Software or, alternatively, in accordance with the terms contained in
 | 
			
		||||
** a written agreement between you and Nokia.
 | 
			
		||||
**
 | 
			
		||||
** GNU Lesser General Public License Usage
 | 
			
		||||
**
 | 
			
		||||
** Alternatively, this file may be used under the terms of the GNU Lesser
 | 
			
		||||
** General Public License version 2.1 as published by the Free Software
 | 
			
		||||
** Foundation and appearing in the file LICENSE.LGPL included in the
 | 
			
		||||
** packaging of this file.  Please review the following information to
 | 
			
		||||
** ensure the GNU Lesser General Public License version 2.1 requirements
 | 
			
		||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 | 
			
		||||
**
 | 
			
		||||
** If you are unsure which license is appropriate for your use, please
 | 
			
		||||
** contact the sales department at http://qt.nokia.com/contact.
 | 
			
		||||
**
 | 
			
		||||
**************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "CppToolsPlugin.h"
 | 
			
		||||
#include "cpprefactoringchanges.h"
 | 
			
		||||
#include "InsertionPointLocator.h"
 | 
			
		||||
 | 
			
		||||
#include <AST.h>
 | 
			
		||||
#include <ASTVisitor.h>
 | 
			
		||||
#include <TranslationUnit.h>
 | 
			
		||||
 | 
			
		||||
using namespace CPlusPlus;
 | 
			
		||||
using namespace CppTools;
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
static QString generate(InsertionPointLocator::AccessSpec xsSpec)
 | 
			
		||||
{
 | 
			
		||||
    switch (xsSpec) {
 | 
			
		||||
    default:
 | 
			
		||||
    case InsertionPointLocator::Public:
 | 
			
		||||
        return QLatin1String("public:\n");
 | 
			
		||||
 | 
			
		||||
    case InsertionPointLocator::Protected:
 | 
			
		||||
        return QLatin1String("protected:\n");
 | 
			
		||||
 | 
			
		||||
    case InsertionPointLocator::Private:
 | 
			
		||||
        return QLatin1String("private:\n");
 | 
			
		||||
 | 
			
		||||
    case InsertionPointLocator::PublicSlot:
 | 
			
		||||
        return QLatin1String("public slots:\n");
 | 
			
		||||
 | 
			
		||||
    case InsertionPointLocator::ProtectedSlot:
 | 
			
		||||
        return QLatin1String("protected slots:\n");
 | 
			
		||||
 | 
			
		||||
    case InsertionPointLocator::PrivateSlot:
 | 
			
		||||
        return QLatin1String("private slots:\n");
 | 
			
		||||
 | 
			
		||||
    case InsertionPointLocator::Signals:
 | 
			
		||||
        return QLatin1String("signals:\n");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int ordering(InsertionPointLocator::AccessSpec xsSpec)
 | 
			
		||||
{
 | 
			
		||||
    static QList<InsertionPointLocator::AccessSpec> order = QList<InsertionPointLocator::AccessSpec>()
 | 
			
		||||
            << InsertionPointLocator::Public
 | 
			
		||||
            << InsertionPointLocator::PublicSlot
 | 
			
		||||
            << InsertionPointLocator::Signals
 | 
			
		||||
            << InsertionPointLocator::Protected
 | 
			
		||||
            << InsertionPointLocator::ProtectedSlot
 | 
			
		||||
            << InsertionPointLocator::PrivateSlot
 | 
			
		||||
            << InsertionPointLocator::Private
 | 
			
		||||
            ;
 | 
			
		||||
 | 
			
		||||
    return order.indexOf(xsSpec);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct AccessRange
 | 
			
		||||
{
 | 
			
		||||
    unsigned start;
 | 
			
		||||
    unsigned end;
 | 
			
		||||
    InsertionPointLocator::AccessSpec xsSpec;
 | 
			
		||||
 | 
			
		||||
    AccessRange()
 | 
			
		||||
        : start(0)
 | 
			
		||||
        , end(0)
 | 
			
		||||
        , xsSpec(InsertionPointLocator::Invalid)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    AccessRange(unsigned start, unsigned end, InsertionPointLocator::AccessSpec xsSpec)
 | 
			
		||||
        : start(start)
 | 
			
		||||
        , end(end)
 | 
			
		||||
        , xsSpec(xsSpec)
 | 
			
		||||
    {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class FindInClass: public ASTVisitor
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    FindInClass(const Document::Ptr &doc, const Class *clazz, InsertionPointLocator::AccessSpec xsSpec)
 | 
			
		||||
        : ASTVisitor(doc->translationUnit())
 | 
			
		||||
        , _doc(doc)
 | 
			
		||||
        , _clazz(clazz)
 | 
			
		||||
        , _xsSpec(xsSpec)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    InsertionLocation operator()()
 | 
			
		||||
    {
 | 
			
		||||
        _result = InsertionLocation();
 | 
			
		||||
 | 
			
		||||
        AST *ast = translationUnit()->ast();
 | 
			
		||||
        accept(ast);
 | 
			
		||||
 | 
			
		||||
        return _result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    using ASTVisitor::visit;
 | 
			
		||||
 | 
			
		||||
    bool visit(ClassSpecifierAST *ast)
 | 
			
		||||
    {
 | 
			
		||||
        if (!ast->lbrace_token || !ast->rbrace_token)
 | 
			
		||||
            return true;
 | 
			
		||||
        if (!ast->symbol || !ast->symbol->isEqualTo(_clazz))
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        QList<AccessRange> ranges = collectAccessRanges(
 | 
			
		||||
                    ast->member_specifier_list,
 | 
			
		||||
                    tokenKind(ast->classkey_token) == T_CLASS ? InsertionPointLocator::Private : InsertionPointLocator::Public,
 | 
			
		||||
                    ast->lbrace_token,
 | 
			
		||||
                    ast->rbrace_token);
 | 
			
		||||
 | 
			
		||||
        unsigned beforeToken = 0;
 | 
			
		||||
        bool needsPrefix = false;
 | 
			
		||||
        bool needsSuffix = false;
 | 
			
		||||
        findMatch(ranges, _xsSpec, beforeToken, needsPrefix, needsSuffix);
 | 
			
		||||
 | 
			
		||||
        unsigned line = 0, column = 0;
 | 
			
		||||
        getTokenStartPosition(beforeToken, &line, &column);
 | 
			
		||||
 | 
			
		||||
        QString prefix;
 | 
			
		||||
        if (needsPrefix)
 | 
			
		||||
            prefix = generate(_xsSpec);
 | 
			
		||||
 | 
			
		||||
        QString suffix;
 | 
			
		||||
        if (needsSuffix)
 | 
			
		||||
            suffix = QLatin1Char('\n');
 | 
			
		||||
 | 
			
		||||
        _result = InsertionLocation(_doc->fileName(), prefix, suffix,
 | 
			
		||||
                                    line, column);
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void findMatch(const QList<AccessRange> &ranges,
 | 
			
		||||
                          InsertionPointLocator::AccessSpec xsSpec,
 | 
			
		||||
                          unsigned &beforeToken,
 | 
			
		||||
                          bool &needsPrefix,
 | 
			
		||||
                          bool &needsSuffix)
 | 
			
		||||
    {
 | 
			
		||||
        Q_ASSERT(!ranges.isEmpty());
 | 
			
		||||
        const int lastIndex = ranges.size() - 1;
 | 
			
		||||
 | 
			
		||||
        // try an exact match, and ignore the first (default) access spec:
 | 
			
		||||
        for (int i = lastIndex; i > 0; --i) {
 | 
			
		||||
            const AccessRange &range = ranges.at(i);
 | 
			
		||||
            if (range.xsSpec == xsSpec) {
 | 
			
		||||
                beforeToken = range.end;
 | 
			
		||||
                needsPrefix = false;
 | 
			
		||||
                needsSuffix = (i != lastIndex);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // try to find a fitting access spec to insert XXX:
 | 
			
		||||
        for (int i = lastIndex; i > 0; --i) {
 | 
			
		||||
            const AccessRange ¤t = ranges.at(i);
 | 
			
		||||
 | 
			
		||||
            if (ordering(xsSpec) > ordering(current.xsSpec)) {
 | 
			
		||||
                beforeToken = current.end;
 | 
			
		||||
                needsPrefix = true;
 | 
			
		||||
                needsSuffix = (i != lastIndex);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // otherwise:
 | 
			
		||||
        beforeToken = ranges.first().end;
 | 
			
		||||
        needsPrefix = true;
 | 
			
		||||
        needsSuffix = (ranges.size() != 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QList<AccessRange> collectAccessRanges(DeclarationListAST *decls,
 | 
			
		||||
                                           InsertionPointLocator::AccessSpec initialXs,
 | 
			
		||||
                                           int firstRangeStart,
 | 
			
		||||
                                           int lastRangeEnd) const
 | 
			
		||||
    {
 | 
			
		||||
        QList<AccessRange> ranges;
 | 
			
		||||
        ranges.append(AccessRange(firstRangeStart, lastRangeEnd, initialXs));
 | 
			
		||||
 | 
			
		||||
        for (DeclarationListAST *iter = decls; iter; iter = iter->next) {
 | 
			
		||||
            DeclarationAST *decl = iter->value;
 | 
			
		||||
 | 
			
		||||
            if (AccessDeclarationAST *xsDecl = decl->asAccessDeclaration()) {
 | 
			
		||||
                const unsigned token = xsDecl->access_specifier_token;
 | 
			
		||||
                int newXsSpec = initialXs;
 | 
			
		||||
                bool isSlot = xsDecl->slots_token
 | 
			
		||||
                        && tokenKind(xsDecl->slots_token) == T_Q_SLOTS;
 | 
			
		||||
 | 
			
		||||
                switch (tokenKind(token)) {
 | 
			
		||||
                case T_PUBLIC:
 | 
			
		||||
                    newXsSpec = isSlot ? InsertionPointLocator::PublicSlot
 | 
			
		||||
                                       : InsertionPointLocator::Public;
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case T_PROTECTED:
 | 
			
		||||
                    newXsSpec = isSlot ? InsertionPointLocator::ProtectedSlot
 | 
			
		||||
                                       : InsertionPointLocator::Protected;
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case T_PRIVATE:
 | 
			
		||||
                    newXsSpec = isSlot ? InsertionPointLocator::PrivateSlot
 | 
			
		||||
                                       : InsertionPointLocator::Private;
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case T_Q_SIGNALS:
 | 
			
		||||
                    newXsSpec = InsertionPointLocator::Signals;
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case T_Q_SLOTS: {
 | 
			
		||||
                    newXsSpec = ranges.last().xsSpec | InsertionPointLocator::SlotBit;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                default:
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (newXsSpec != ranges.last().xsSpec) {
 | 
			
		||||
                    ranges.last().end = token;
 | 
			
		||||
                    ranges.append(AccessRange(token, lastRangeEnd, (InsertionPointLocator::AccessSpec) newXsSpec));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ranges.last().end = lastRangeEnd;
 | 
			
		||||
        return ranges;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Document::Ptr _doc;
 | 
			
		||||
    const Class *_clazz;
 | 
			
		||||
    InsertionPointLocator::AccessSpec _xsSpec;
 | 
			
		||||
 | 
			
		||||
    InsertionLocation _result;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // end of anonymous namespace
 | 
			
		||||
 | 
			
		||||
InsertionLocation::InsertionLocation()
 | 
			
		||||
    : m_line(0)
 | 
			
		||||
    , m_column(0)
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
InsertionLocation::InsertionLocation(const QString &fileName,
 | 
			
		||||
                                     const QString &prefix,
 | 
			
		||||
                                     const QString &suffix,
 | 
			
		||||
                                     unsigned line, unsigned column)
 | 
			
		||||
    : m_fileName(fileName)
 | 
			
		||||
    , m_prefix(prefix)
 | 
			
		||||
    , m_suffix(suffix)
 | 
			
		||||
    , m_line(line)
 | 
			
		||||
    , m_column(column)
 | 
			
		||||
{}
 | 
			
		||||
 | 
			
		||||
InsertionPointLocator::InsertionPointLocator(CppRefactoringChanges *refactoringChanges)
 | 
			
		||||
    : m_refactoringChanges(refactoringChanges)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
InsertionLocation InsertionPointLocator::methodDeclarationInClass(
 | 
			
		||||
    const QString &fileName,
 | 
			
		||||
    const Class *clazz,
 | 
			
		||||
    AccessSpec xsSpec) const
 | 
			
		||||
{
 | 
			
		||||
    const Document::Ptr doc = m_refactoringChanges->file(fileName).cppDocument();
 | 
			
		||||
    if (doc) {
 | 
			
		||||
        FindInClass find(doc, clazz, xsSpec);
 | 
			
		||||
        return find();
 | 
			
		||||
    } else {
 | 
			
		||||
        return InsertionLocation();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Currently, we return the end of fileName.cpp
 | 
			
		||||
QList<InsertionLocation> InsertionPointLocator::methodDefinition(
 | 
			
		||||
    Declaration *declaration) const
 | 
			
		||||
{
 | 
			
		||||
    QList<InsertionLocation> result;
 | 
			
		||||
    if (!declaration)
 | 
			
		||||
        return result;
 | 
			
		||||
 | 
			
		||||
    Internal::CppToolsPlugin *cpptools = Internal::CppToolsPlugin::instance();
 | 
			
		||||
 | 
			
		||||
    const QString declFileName = QLatin1String(declaration->fileName());
 | 
			
		||||
    QString target = cpptools->correspondingHeaderOrSource(declFileName);
 | 
			
		||||
    Document::Ptr doc = m_refactoringChanges->file(target).cppDocument();
 | 
			
		||||
    if (doc.isNull())
 | 
			
		||||
        return result;
 | 
			
		||||
 | 
			
		||||
    TranslationUnit *xUnit = doc->translationUnit();
 | 
			
		||||
    unsigned tokenCount = xUnit->tokenCount();
 | 
			
		||||
    if (tokenCount < 2) // no tokens available
 | 
			
		||||
        return result;
 | 
			
		||||
 | 
			
		||||
    unsigned line = 0, column = 0;
 | 
			
		||||
    xUnit->getTokenEndPosition(xUnit->tokenCount() - 2, &line, &column);
 | 
			
		||||
 | 
			
		||||
    const QLatin1String prefix("\n\n");
 | 
			
		||||
    result.append(InsertionLocation(target, prefix, QString(), line, column));
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										115
									
								
								src/plugins/cpptools/insertionpointlocator.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								src/plugins/cpptools/insertionpointlocator.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,115 @@
 | 
			
		||||
/**************************************************************************
 | 
			
		||||
**
 | 
			
		||||
** This file is part of Qt Creator
 | 
			
		||||
**
 | 
			
		||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
 | 
			
		||||
**
 | 
			
		||||
** Contact: Nokia Corporation (qt-info@nokia.com)
 | 
			
		||||
**
 | 
			
		||||
** Commercial Usage
 | 
			
		||||
**
 | 
			
		||||
** Licensees holding valid Qt Commercial licenses may use this file in
 | 
			
		||||
** accordance with the Qt Commercial License Agreement provided with the
 | 
			
		||||
** Software or, alternatively, in accordance with the terms contained in
 | 
			
		||||
** a written agreement between you and Nokia.
 | 
			
		||||
**
 | 
			
		||||
** GNU Lesser General Public License Usage
 | 
			
		||||
**
 | 
			
		||||
** Alternatively, this file may be used under the terms of the GNU Lesser
 | 
			
		||||
** General Public License version 2.1 as published by the Free Software
 | 
			
		||||
** Foundation and appearing in the file LICENSE.LGPL included in the
 | 
			
		||||
** packaging of this file.  Please review the following information to
 | 
			
		||||
** ensure the GNU Lesser General Public License version 2.1 requirements
 | 
			
		||||
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 | 
			
		||||
**
 | 
			
		||||
** If you are unsure which license is appropriate for your use, please
 | 
			
		||||
** contact the sales department at http://qt.nokia.com/contact.
 | 
			
		||||
**
 | 
			
		||||
**************************************************************************/
 | 
			
		||||
 | 
			
		||||
#ifndef INSERTIONPOINTLOCATOR_H
 | 
			
		||||
#define INSERTIONPOINTLOCATOR_H
 | 
			
		||||
 | 
			
		||||
#include "cpptools_global.h"
 | 
			
		||||
 | 
			
		||||
#include <ASTfwd.h>
 | 
			
		||||
#include <CPlusPlusForwardDeclarations.h>
 | 
			
		||||
#include <Symbols.h>
 | 
			
		||||
 | 
			
		||||
#include <cplusplus/CppDocument.h>
 | 
			
		||||
 | 
			
		||||
namespace CppTools {
 | 
			
		||||
 | 
			
		||||
class CppRefactoringChanges;
 | 
			
		||||
 | 
			
		||||
class CPPTOOLS_EXPORT InsertionLocation
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    InsertionLocation();
 | 
			
		||||
    InsertionLocation(const QString &fileName, const QString &prefix,
 | 
			
		||||
                      const QString &suffix, unsigned line, unsigned column);
 | 
			
		||||
 | 
			
		||||
    QString fileName() const
 | 
			
		||||
    { return m_fileName; }
 | 
			
		||||
 | 
			
		||||
    /// \returns The prefix to insert before any other text.
 | 
			
		||||
    QString prefix() const
 | 
			
		||||
    { return m_prefix; }
 | 
			
		||||
 | 
			
		||||
    /// \returns The suffix to insert after the other inserted text.
 | 
			
		||||
    QString suffix() const
 | 
			
		||||
    { return m_suffix; }
 | 
			
		||||
 | 
			
		||||
    /// \returns The line where to insert. The line number is 1-based.
 | 
			
		||||
    unsigned line() const
 | 
			
		||||
    { return m_line; }
 | 
			
		||||
 | 
			
		||||
    /// \returns The column where to insert. The column number is 1-based.
 | 
			
		||||
    unsigned column() const
 | 
			
		||||
    { return m_column; }
 | 
			
		||||
 | 
			
		||||
    bool isValid() const
 | 
			
		||||
    { return !m_fileName.isEmpty() && m_line > 0 && m_column > 0; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    QString m_fileName;
 | 
			
		||||
    QString m_prefix;
 | 
			
		||||
    QString m_suffix;
 | 
			
		||||
    unsigned m_line;
 | 
			
		||||
    unsigned m_column;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class CPPTOOLS_EXPORT InsertionPointLocator
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    enum AccessSpec {
 | 
			
		||||
        Invalid = -1,
 | 
			
		||||
        Signals = 0,
 | 
			
		||||
 | 
			
		||||
        Public = 1,
 | 
			
		||||
        Protected = 2,
 | 
			
		||||
        Private = 3,
 | 
			
		||||
 | 
			
		||||
        SlotBit = 1 << 2,
 | 
			
		||||
 | 
			
		||||
        PublicSlot    = Public    | SlotBit,
 | 
			
		||||
        ProtectedSlot = Protected | SlotBit,
 | 
			
		||||
        PrivateSlot   = Private   | SlotBit,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    InsertionPointLocator(CppRefactoringChanges *refactoringChanges);
 | 
			
		||||
 | 
			
		||||
    InsertionLocation methodDeclarationInClass(const QString &fileName,
 | 
			
		||||
                                               const CPlusPlus::Class *clazz,
 | 
			
		||||
                                               AccessSpec xsSpec) const;
 | 
			
		||||
 | 
			
		||||
    QList<InsertionLocation> methodDefinition(CPlusPlus::Declaration *declaration) const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    CppRefactoringChanges *m_refactoringChanges;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace CppTools
 | 
			
		||||
 | 
			
		||||
#endif // INSERTIONPOINTLOCATOR_H
 | 
			
		||||
		Reference in New Issue
	
	Block a user