cpprefactoringchanges.cpp 8.39 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
hjk's avatar
hjk committed
4
** Contact: http://www.qt-project.org/legal
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8 9 10 11 12 13 14
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
15 16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17 18 19 20 21 22 23 24 25
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
con's avatar
con committed
26 27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
28
****************************************************************************/
29 30

#include "cpprefactoringchanges.h"
31

32
#include "cppqtstyleindenter.h"
33 34
#include "cppcodeformatter.h"
#include "cppmodelmanager.h"
35
#include <projectexplorer/editorconfiguration.h>
36

37
#include <utils/qtcassert.h>
38

Roberto Raggi's avatar
Roberto Raggi committed
39
using namespace CPlusPlus;
40
using namespace CppTools;
41
using namespace Utils;
42

43 44 45 46 47 48 49 50 51 52 53 54 55
class CppTools::CppRefactoringChangesData : public TextEditor::RefactoringChangesData
{
public:
    CppRefactoringChangesData(const Snapshot &snapshot)
        : m_snapshot(snapshot)
        , m_modelManager(Internal::CppModelManager::instance())
        , m_workingCopy(m_modelManager->workingCopy())
    {}

    virtual void indentSelection(const QTextCursor &selection,
                                 const QString &fileName,
                                 const TextEditor::BaseTextEditorWidget *textEditor) const
    {
56 57
        const TextEditor::TabSettings &tabSettings =
            ProjectExplorer::actualTabSettings(fileName, textEditor);
58

59 60 61
        CppQtStyleIndenter indenter;
        indenter.indent(selection.document(), selection, QChar::Null, tabSettings);
    }
62

63 64 65 66
    virtual void reindentSelection(const QTextCursor &selection,
                                   const QString &fileName,
                                   const TextEditor::BaseTextEditorWidget *textEditor) const
    {
67 68 69
        const TextEditor::TabSettings &tabSettings =
            ProjectExplorer::actualTabSettings(fileName, textEditor);

70 71
        CppQtStyleIndenter indenter;
        indenter.reindent(selection.document(), selection, tabSettings);
72 73 74 75 76 77 78
    }

    virtual void fileChanged(const QString &fileName)
    {
        m_modelManager->updateSourceFiles(QStringList(fileName));
    }

79 80 81
    Snapshot m_snapshot;
    CppModelManagerInterface *m_modelManager;
    CppModelManagerInterface::WorkingCopy m_workingCopy;
82 83 84

};

85
CppRefactoringChanges::CppRefactoringChanges(const Snapshot &snapshot)
86
    : RefactoringChanges(new CppRefactoringChangesData(snapshot))
87 88 89
{
}

90
CppRefactoringChangesData *CppRefactoringChanges::data() const
91
{
92
    return static_cast<CppRefactoringChangesData *>(m_data.data());
93 94
}

95
CppRefactoringFilePtr CppRefactoringChanges::file(TextEditor::BaseTextEditorWidget *editor, const Document::Ptr &document)
96
{
97 98 99
    CppRefactoringFilePtr result(new CppRefactoringFile(editor));
    result->setCppDocument(document);
    return result;
100
}
101

102
CppRefactoringFilePtr CppRefactoringChanges::file(const QString &fileName) const
103
{
104 105 106
    CppRefactoringFilePtr result(new CppRefactoringFile(fileName, m_data));
    return result;
}
107

108 109 110 111
CppRefactoringFileConstPtr CppRefactoringChanges::fileNoEditor(const QString &fileName) const
{
    QTextDocument *document = 0;
    if (data()->m_workingCopy.contains(fileName))
112
        document = new QTextDocument(QString::fromUtf8(data()->m_workingCopy.source(fileName)));
113 114
    CppRefactoringFilePtr result(new CppRefactoringFile(document, fileName));
    result->m_data = m_data;
115

116 117 118
    Document::Ptr cppDocument = data()->m_snapshot.document(fileName);
    if (cppDocument)
        result->setCppDocument(cppDocument);
119

120
    return result;
121
}
122

123
const Snapshot &CppRefactoringChanges::snapshot() const
124
{
125
    return data()->m_snapshot;
126
}
127

128 129
CppRefactoringFile::CppRefactoringFile(const QString &fileName, const QSharedPointer<TextEditor::RefactoringChangesData> &data)
    : RefactoringFile(fileName, data)
130
{
131
    const Snapshot &snapshot = this->data()->m_snapshot;
132 133
    m_cppDocument = snapshot.document(fileName);
}
134

135 136 137 138 139 140 141
CppRefactoringFile::CppRefactoringFile(QTextDocument *document, const QString &fileName)
    : RefactoringFile(document, fileName)
{ }

CppRefactoringFile::CppRefactoringFile(TextEditor::BaseTextEditorWidget *editor)
    : RefactoringFile(editor)
{ }
142

143 144
Document::Ptr CppRefactoringFile::cppDocument() const
{
145 146
    if (!m_cppDocument || !m_cppDocument->translationUnit() ||
            !m_cppDocument->translationUnit()->ast()) {
147
        const QByteArray source = document()->toPlainText().toUtf8();
148
        const QString name = fileName();
149
        const Snapshot &snapshot = data()->m_snapshot;
150

151
        m_cppDocument = snapshot.preprocessedDocument(source, name);
152 153 154 155 156 157
        m_cppDocument->check();
    }

    return m_cppDocument;
}

158 159 160 161 162
void CppRefactoringFile::setCppDocument(Document::Ptr document)
{
    m_cppDocument = document;
}

163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
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
{
233
    unsigned end = ast->lastToken();
234
    QTC_ASSERT(end > 0, return -1);
235
    return endOf(end - 1);
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
}

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);
}

257 258 259 260 261 262
CppRefactoringChangesData *CppRefactoringFile::data() const
{
    return static_cast<CppRefactoringChangesData *>(m_data.data());
}

void CppRefactoringFile::fileChanged()
263
{
264 265
    m_cppDocument.clear();
    RefactoringFile::fileChanged();
266
}