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"
|