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