1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include "clangtoolsplugin.h"
27
28 #include "clangtool.h"
29 #include "clangtoolsconstants.h"
30 #include "clangtoolsprojectsettings.h"
31 #include "clangtoolsprojectsettingswidget.h"
32 #include "documentclangtoolrunner.h"
33 #include "documentquickfixfactory.h"
34 #include "settingswidget.h"
35
36 #ifdef WITH_TESTS
37 #include "clangtoolspreconfiguredsessiontests.h"
38 #include "clangtoolsunittests.h"
39 #endif
40
41 #include <utils/mimetypes/mimedatabase.h>
42 #include <utils/mimetypes/mimetype.h>
43 #include <utils/qtcassert.h>
44
45 #include <coreplugin/actionmanager/actioncontainer.h>
46 #include <coreplugin/actionmanager/actionmanager.h>
47 #include <coreplugin/actionmanager/command.h>
48 #include <coreplugin/coreconstants.h>
49 #include <coreplugin/editormanager/editormanager.h>
50 #include <coreplugin/icontext.h>
51 #include <coreplugin/icore.h>
52
53 #include <cpptools/cpptoolsconstants.h>
54 #include <cpptools/cppmodelmanager.h>
55
56 #include <texteditor/texteditor.h>
57
58 #include <cppeditor/cppeditorconstants.h>
59
60 #include <projectexplorer/kitinformation.h>
61 #include <projectexplorer/projectpanelfactory.h>
62 #include <projectexplorer/target.h>
63 #include <projectexplorer/taskhub.h>
64
65 #include <QAction>
66 #include <QDebug>
67 #include <QMainWindow>
68 #include <QMenu>
69 #include <QMessageBox>
70 #include <QToolBar>
71
72 using namespace Core;
73 using namespace ProjectExplorer;
74
75 namespace ClangTools {
76 namespace Internal {
77
78 static ProjectPanelFactory *m_projectPanelFactoryInstance = nullptr;
79
projectPanelFactory()80 ProjectPanelFactory *projectPanelFactory()
81 {
82 return m_projectPanelFactoryInstance;
83 }
84
85 class ClangToolsPluginPrivate
86 {
87 public:
ClangToolsPluginPrivate()88 ClangToolsPluginPrivate()
89 : quickFixFactory(
90 [this](const Utils::FilePath &filePath) { return runnerForFilePath(filePath); })
91 {}
92
runnerForFilePath(const Utils::FilePath & filePath)93 DocumentClangToolRunner *runnerForFilePath(const Utils::FilePath &filePath)
94 {
95 for (DocumentClangToolRunner *runner : qAsConst(documentRunners)) {
96 if (runner->filePath() == filePath)
97 return runner;
98 }
99 return nullptr;
100 }
101
102 ClangTool clangTool;
103 ClangToolsOptionsPage optionsPage;
104 QMap<Core::IDocument *, DocumentClangToolRunner *> documentRunners;
105 DocumentQuickFixFactory quickFixFactory;
106 };
107
~ClangToolsPlugin()108 ClangToolsPlugin::~ClangToolsPlugin()
109 {
110 delete d;
111 }
112
initialize(const QStringList & arguments,QString * errorString)113 bool ClangToolsPlugin::initialize(const QStringList &arguments, QString *errorString)
114 {
115 Q_UNUSED(arguments)
116 Q_UNUSED(errorString)
117
118 TaskHub::addCategory(taskCategory(), tr("Clang Tools"));
119
120 // Import tidy/clazy diagnostic configs from CppTools now
121 // instead of at opening time of the settings page
122 ClangToolsSettings::instance();
123
124 d = new ClangToolsPluginPrivate;
125
126 registerAnalyzeActions();
127
128 auto panelFactory = m_projectPanelFactoryInstance = new ProjectPanelFactory;
129 panelFactory->setPriority(100);
130 panelFactory->setId(Constants::PROJECT_PANEL_ID);
131 panelFactory->setDisplayName(tr("Clang Tools"));
132 panelFactory->setCreateWidgetFunction([](Project *project) { return new ProjectSettingsWidget(project); });
133 ProjectPanelFactory::registerFactory(panelFactory);
134
135 connect(Core::EditorManager::instance(),
136 &Core::EditorManager::currentEditorChanged,
137 this,
138 &ClangToolsPlugin::onCurrentEditorChanged);
139
140 return true;
141 }
142
onCurrentEditorChanged()143 void ClangToolsPlugin::onCurrentEditorChanged()
144 {
145 for (Core::IEditor *editor : Core::EditorManager::visibleEditors()) {
146 IDocument *document = editor->document();
147 if (d->documentRunners.contains(document))
148 continue;
149 auto runner = new DocumentClangToolRunner(document);
150 connect(runner, &DocumentClangToolRunner::destroyed, this, [this, document]() {
151 d->documentRunners.remove(document);
152 });
153 d->documentRunners[document] = runner;
154 }
155 }
156
registerAnalyzeActions()157 void ClangToolsPlugin::registerAnalyzeActions()
158 {
159 ActionManager::registerAction(d->clangTool.startAction(), Constants::RUN_ON_PROJECT);
160 Command *cmd = ActionManager::registerAction(d->clangTool.startOnCurrentFileAction(),
161 Constants::RUN_ON_CURRENT_FILE);
162 ActionContainer *mtoolscpp = ActionManager::actionContainer(CppTools::Constants::M_TOOLS_CPP);
163 if (mtoolscpp)
164 mtoolscpp->addAction(cmd);
165
166 Core::ActionContainer *mcontext = Core::ActionManager::actionContainer(
167 CppEditor::Constants::M_CONTEXT);
168 if (mcontext)
169 mcontext->addAction(cmd, CppEditor::Constants::G_CONTEXT_FIRST);
170
171 // add button to tool bar of C++ source files
172 connect(EditorManager::instance(), &EditorManager::editorOpened, this, [this, cmd](IEditor *editor) {
173 if (editor->document()->filePath().isEmpty()
174 || !Utils::mimeTypeForName(editor->document()->mimeType()).inherits("text/x-c++src"))
175 return;
176 auto *textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor);
177 if (!textEditor)
178 return;
179 TextEditor::TextEditorWidget *widget = textEditor->editorWidget();
180 if (!widget)
181 return;
182 const QIcon icon = Utils::Icon({{":/debugger/images/debugger_singleinstructionmode.png",
183 Utils::Theme::IconsBaseColor}})
184 .icon();
185 QAction *action = widget->toolBar()->addAction(icon, tr("Analyze File"), [this, editor]() {
186 d->clangTool.startTool(editor->document()->filePath());
187 });
188 cmd->augmentActionWithShortcutToolTip(action);
189 });
190 }
191
createTestObjects() const192 QVector<QObject *> ClangToolsPlugin::createTestObjects() const
193 {
194 QVector<QObject *> tests;
195 #ifdef WITH_TESTS
196 tests << new PreconfiguredSessionTests;
197 tests << new ClangToolsUnitTests;
198 #endif
199 return tests;
200 }
201
202 } // namespace Internal
203 } // namespace ClangTools
204