File: headerguardassistant.cpp

package info (click to toggle)
kdevelop 4%3A24.12.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 71,888 kB
  • sloc: cpp: 290,869; python: 3,626; javascript: 3,518; sh: 1,316; ansic: 703; xml: 401; php: 95; lisp: 66; makefile: 31; sed: 12
file content (119 lines) | stat: -rw-r--r-- 4,198 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/*
    SPDX-FileCopyrightText: 2018, 2019 Amish K. Naidu <amhndu@gmail.com>

    SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/

#include "headerguardassistant.h"
#include "util/clangutils.h"
#include "util/clangtypes.h"

#include <language/codegen/documentchangeset.h>
#include <language/codegen/coderepresentation.h>
#include <language/duchain/duchainlock.h>

#include <QDir>
#include <QRegularExpression>

#include <algorithm>


enum class GuardType
{
    Pragma,
    Macro
};

class AddHeaderGuardAction
    : public KDevelop::IAssistantAction
{
    Q_OBJECT

public:
    AddHeaderGuardAction(const GuardType type, const int startLine, const KDevelop::IndexedString& path)
        : m_type(type)
        , m_startLine(startLine)
        , m_path(path)
    {
    }

    virtual ~AddHeaderGuardAction() override = default;

    QString description() const override
    {
        switch (m_type) {
            case GuardType::Pragma: return i18n("Add #pragma once");
            case GuardType::Macro: return i18n("Add macro-based #ifndef/#define/#endif header guard");
        }
        return {};
    }

    void execute() override
    {
        KDevelop::DocumentChangeSet changes;
        switch (m_type) {
            case GuardType::Pragma:
            {
                KDevelop::DocumentChange change(m_path, KTextEditor::Range(m_startLine, 0, m_startLine, 0), QString(),
                                                QStringLiteral("#pragma once\n\n"));
                changes.addChange(change);
                break;
            }
            case GuardType::Macro:
            {
                const QString macro = m_path.toUrl()
                        .fileName(QUrl::PrettyDecoded)
                        .replace(QRegularExpression(QStringLiteral("[^a-zA-Z0-9]")), QStringLiteral(" "))
                        .simplified()
                        .toUpper()
                        .replace(QLatin1Char(' '), QLatin1Char('_'))
                        .append(QLatin1String("_INCLUDED"));

                const auto representation = KDevelop::createCodeRepresentation(m_path);
                const auto lastLine = representation->lines() - 1;
                const auto lastColumn = representation->line(lastLine).length();

                // Add the #endif change before so that it applies correctly in case lastLine == m_startline
                changes.addChange(KDevelop::DocumentChange(m_path,
                                                           KTextEditor::Range(lastLine, lastColumn, lastLine, lastColumn),
                                                           QString(),
                                                           QStringLiteral("\n#endif // %1").arg(macro)));
                changes.addChange(KDevelop::DocumentChange(m_path,
                                                           KTextEditor::Range(m_startLine, 0, m_startLine, 0),
                                                           QString(),
                                                           QStringLiteral("#ifndef %1\n#define %1\n\n").arg(macro)));
                break;
            }
        }

        KDevelop::DUChainReadLocker lock;
        changes.setReplacementPolicy(KDevelop::DocumentChangeSet::WarnOnFailedChange);
        changes.applyAllChanges();
        emit executed(this);
    }

private:
    const GuardType m_type;
    const int m_startLine;
    const KDevelop::IndexedString m_path;
};

HeaderGuardAssistant::HeaderGuardAssistant(const CXTranslationUnit unit, const CXFile file)
    : m_line(std::max(ClangUtils::skipTopCommentBlock(unit, file), 1u) - 1) // skip license etc
    , m_path(QDir(ClangString(clang_getFileName(file)).toString()).canonicalPath())
{
}

QString HeaderGuardAssistant::title() const
{
    return QStringLiteral("Fix-Header");
}

void HeaderGuardAssistant::createActions()
{
    addAction(KDevelop::IAssistantAction::Ptr{new AddHeaderGuardAction(GuardType::Pragma, m_line, m_path)});
    addAction(KDevelop::IAssistantAction::Ptr{new AddHeaderGuardAction(GuardType::Macro, m_line, m_path)});
}

#include "headerguardassistant.moc"
#include "moc_headerguardassistant.cpp"