File indexing completed on 2024-05-12 04:39:12
0001 /* 0002 SPDX-FileCopyrightText: 2018, 2019 Amish K. Naidu <amhndu@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "headerguardassistant.h" 0008 #include "util/clangutils.h" 0009 #include "util/clangtypes.h" 0010 0011 #include <language/codegen/documentchangeset.h> 0012 #include <language/codegen/coderepresentation.h> 0013 #include <language/duchain/duchainlock.h> 0014 0015 #include <QDir> 0016 #include <QRegularExpression> 0017 0018 #include <algorithm> 0019 0020 0021 enum class GuardType 0022 { 0023 Pragma, 0024 Macro 0025 }; 0026 0027 class AddHeaderGuardAction 0028 : public KDevelop::IAssistantAction 0029 { 0030 Q_OBJECT 0031 0032 public: 0033 AddHeaderGuardAction(const GuardType type, const int startLine, const KDevelop::IndexedString& path) 0034 : m_type(type) 0035 , m_startLine(startLine) 0036 , m_path(path) 0037 { 0038 } 0039 0040 virtual ~AddHeaderGuardAction() override = default; 0041 0042 QString description() const override 0043 { 0044 switch (m_type) { 0045 case GuardType::Pragma: return i18n("Add #pragma once"); 0046 case GuardType::Macro: return i18n("Add macro-based #ifndef/#define/#endif header guard"); 0047 } 0048 return {}; 0049 } 0050 0051 void execute() override 0052 { 0053 KDevelop::DocumentChangeSet changes; 0054 switch (m_type) { 0055 case GuardType::Pragma: 0056 { 0057 KDevelop::DocumentChange change(m_path, KTextEditor::Range(m_startLine, 0, m_startLine, 0), QString(), 0058 QStringLiteral("#pragma once\n\n")); 0059 changes.addChange(change); 0060 break; 0061 } 0062 case GuardType::Macro: 0063 { 0064 const QString macro = m_path.toUrl() 0065 .fileName(QUrl::PrettyDecoded) 0066 .replace(QRegularExpression(QStringLiteral("[^a-zA-Z0-9]")), QStringLiteral(" ")) 0067 .simplified() 0068 .toUpper() 0069 .replace(QLatin1Char(' '), QLatin1Char('_')) 0070 .append(QLatin1String("_INCLUDED")); 0071 0072 const auto representation = KDevelop::createCodeRepresentation(m_path); 0073 const auto lastLine = representation->lines() - 1; 0074 const auto lastColumn = representation->line(lastLine).length(); 0075 0076 // Add the #endif change before so that it applies correctly in case lastLine == m_startline 0077 changes.addChange(KDevelop::DocumentChange(m_path, 0078 KTextEditor::Range(lastLine, lastColumn, lastLine, lastColumn), 0079 QString(), 0080 QStringLiteral("\n#endif // %1").arg(macro))); 0081 changes.addChange(KDevelop::DocumentChange(m_path, 0082 KTextEditor::Range(m_startLine, 0, m_startLine, 0), 0083 QString(), 0084 QStringLiteral("#ifndef %1\n#define %1\n\n").arg(macro))); 0085 break; 0086 } 0087 } 0088 0089 KDevelop::DUChainReadLocker lock; 0090 changes.setReplacementPolicy(KDevelop::DocumentChangeSet::WarnOnFailedChange); 0091 changes.applyAllChanges(); 0092 emit executed(this); 0093 } 0094 0095 private: 0096 const GuardType m_type; 0097 const int m_startLine; 0098 const KDevelop::IndexedString m_path; 0099 }; 0100 0101 HeaderGuardAssistant::HeaderGuardAssistant(const CXTranslationUnit unit, const CXFile file) 0102 : m_line(std::max(ClangUtils::skipTopCommentBlock(unit, file), 1u) - 1) // skip license etc 0103 , m_path(QDir(ClangString(clang_getFileName(file)).toString()).canonicalPath()) 0104 { 0105 } 0106 0107 QString HeaderGuardAssistant::title() const 0108 { 0109 return QStringLiteral("Fix-Header"); 0110 } 0111 0112 void HeaderGuardAssistant::createActions() 0113 { 0114 addAction(KDevelop::IAssistantAction::Ptr{new AddHeaderGuardAction(GuardType::Pragma, m_line, m_path)}); 0115 addAction(KDevelop::IAssistantAction::Ptr{new AddHeaderGuardAction(GuardType::Macro, m_line, m_path)}); 0116 } 0117 0118 #include "headerguardassistant.moc" 0119 #include "moc_headerguardassistant.cpp"