1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 Sergey Morozov
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 "cppcheckplugin.h"
27 #include "cppcheckconstants.h"
28 #include "cppcheckdiagnosticview.h"
29 #include "cppchecktextmarkmanager.h"
30 #include "cppchecktool.h"
31 #include "cppchecktrigger.h"
32 #include "cppcheckdiagnosticsmodel.h"
33 #include "cppcheckmanualrundialog.h"
34 
35 #include <projectexplorer/session.h>
36 #include <projectexplorer/projectexplorer.h>
37 #include <projectexplorer/project.h>
38 #include <projectexplorer/kitinformation.h>
39 #include <projectexplorer/target.h>
40 
41 #include <coreplugin/actionmanager/actioncontainer.h>
42 #include <coreplugin/actionmanager/actionmanager.h>
43 
44 #include <debugger/analyzer/analyzerconstants.h>
45 #include <debugger/debuggermainwindow.h>
46 
47 #include <utils/qtcassert.h>
48 #include <utils/utilsicons.h>
49 
50 namespace Cppcheck {
51 namespace Internal {
52 
53 class CppcheckPluginPrivate final : public QObject
54 {
55 public:
56     explicit CppcheckPluginPrivate();
57     CppcheckTextMarkManager marks;
58     CppcheckTool tool;
59     CppcheckTrigger trigger;
60     CppcheckOptionsPage options;
61     DiagnosticsModel manualRunModel;
62     CppcheckTool manualRunTool;
63     Utils::Perspective perspective{Constants::PERSPECTIVE_ID, CppcheckPlugin::tr("Cppcheck")};
64     QAction *manualRunAction;
65 
66     void startManualRun();
67     void updateManualRunAction();
68 };
69 
CppcheckPluginPrivate()70 CppcheckPluginPrivate::CppcheckPluginPrivate() :
71     tool(marks, Constants::CHECK_PROGRESS_ID),
72     trigger(marks, tool),
73     options(tool, trigger),
74     manualRunTool(manualRunModel, Constants::MANUAL_CHECK_PROGRESS_ID)
75 {
76     manualRunTool.updateOptions(tool.options());
77 
78     auto manualRunView = new DiagnosticView;
79     manualRunView->setModel(&manualRunModel);
80     perspective.addWindow(manualRunView, Utils::Perspective::SplitVertical, nullptr);
81 
82     {
83         // Go to previous diagnostic
84         auto action = new QAction(this);
85         action->setEnabled(false);
86         action->setIcon(Utils::Icons::PREV_TOOLBAR.icon());
87         action->setToolTip(CppcheckPlugin::tr("Go to previous diagnostic."));
88         connect(action, &QAction::triggered,
89                 manualRunView, &Debugger::DetailedErrorView::goBack);
90         connect (&manualRunModel, &DiagnosticsModel::hasDataChanged,
91                 action, &QAction::setEnabled);
92         perspective.addToolBarAction(action);
93     }
94 
95     {
96         // Go to next diagnostic
97         auto action = new QAction(this);
98         action->setEnabled(false);
99         action->setIcon(Utils::Icons::NEXT_TOOLBAR.icon());
100         action->setToolTip(CppcheckPlugin::tr("Go to next diagnostic."));
101         connect(action, &QAction::triggered,
102                 manualRunView, &Debugger::DetailedErrorView::goNext);
103         connect (&manualRunModel, &DiagnosticsModel::hasDataChanged,
104                 action, &QAction::setEnabled);
105         perspective.addToolBarAction(action);
106     }
107 
108     {
109         // Clear data
110         auto action = new QAction(this);
111         action->setEnabled(false);
112         action->setIcon(Utils::Icons::CLEAN_TOOLBAR.icon());
113         action->setToolTip(CppcheckPlugin::tr("Clear"));
114         connect(action, &QAction::triggered,
115                 &manualRunModel, &DiagnosticsModel::clear);
116         connect (&manualRunModel, &DiagnosticsModel::hasDataChanged,
117                 action, &QAction::setEnabled);
118         perspective.addToolBarAction(action);
119     }
120 }
121 
startManualRun()122 void CppcheckPluginPrivate::startManualRun() {
123     auto project = ProjectExplorer::SessionManager::startupProject();
124     if (!project)
125         return;
126 
127     ManualRunDialog dialog(manualRunTool.options(), project);
128     if (dialog.exec() == ManualRunDialog::Rejected)
129         return;
130 
131     manualRunModel.clear();
132 
133     const auto files = dialog.filePaths();
134     if (files.isEmpty())
135         return;
136 
137     manualRunTool.setProject(project);
138     manualRunTool.updateOptions(dialog.options());
139     manualRunTool.check(files);
140     perspective.select();
141 }
142 
updateManualRunAction()143 void CppcheckPluginPrivate::updateManualRunAction()
144 {
145     using namespace ProjectExplorer;
146     const Project *project = SessionManager::startupProject();
147     const Target *target = SessionManager::startupTarget();
148     const Utils::Id cxx = ProjectExplorer::Constants::CXX_LANGUAGE_ID;
149     const bool canRun = target && project->projectLanguages().contains(cxx)
150                   && ToolChainKitAspect::cxxToolChain(target->kit());
151     manualRunAction->setEnabled(canRun);
152 }
153 
154 CppcheckPlugin::CppcheckPlugin() = default;
155 
156 CppcheckPlugin::~CppcheckPlugin() = default;
157 
initialize(const QStringList & arguments,QString * errorString)158 bool CppcheckPlugin::initialize(const QStringList &arguments, QString *errorString)
159 {
160     Q_UNUSED(arguments)
161     Q_UNUSED(errorString)
162 
163     d.reset(new CppcheckPluginPrivate);
164 
165     using namespace Core;
166     ActionContainer *menu = ActionManager::actionContainer(Debugger::Constants::M_DEBUG_ANALYZER);
167 
168     {
169         auto action = new QAction(tr("Cppcheck..."), this);
170         menu->addAction(ActionManager::registerAction(action, Constants::MANUAL_RUN_ACTION),
171                         Debugger::Constants::G_ANALYZER_TOOLS);
172         connect(action, &QAction::triggered,
173                 d.get(), &CppcheckPluginPrivate::startManualRun);
174         d->manualRunAction = action;
175     }
176 
177     using ProjectExplorer::ProjectExplorerPlugin;
178     connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::runActionsUpdated,
179             d.get(), &CppcheckPluginPrivate::updateManualRunAction);
180     d->updateManualRunAction();
181 
182     return true;
183 }
184 
185 } // namespace Internal
186 } // namespace Cppcheck
187