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 "clangjobrequest.h"
27
28 #include "clangcompletecodejob.h"
29 #include "clangfollowsymboljob.h"
30 #include "clangparsesupportivetranslationunitjob.h"
31 #include "clangrequestannotationsjob.h"
32 #include "clangrequestreferencesjob.h"
33 #include "clangrequesttooltipjob.h"
34 #include "clangresumedocumentjob.h"
35 #include "clangsuspenddocumentjob.h"
36 #include "clangupdateannotationsjob.h"
37 #include "clangupdateextraannotationsjob.h"
38
39 #include <clangsupport/clangcodemodelclientinterface.h>
40 #include <clangsupport/completionsmessage.h>
41 #include <clangsupport/followsymbolmessage.h>
42 #include <clangsupport/referencesmessage.h>
43 #include <clangsupport/tooltipmessage.h>
44
45 #include <utils/qtcassert.h>
46
47 #include <QFileInfo>
48
49 #include <ostream>
50
51 namespace ClangBackEnd {
52
53 #define RETURN_TEXT_FOR_CASE(enumValue) case JobRequest::Type::enumValue: return #enumValue
JobRequestTypeToText(JobRequest::Type type)54 static const char *JobRequestTypeToText(JobRequest::Type type)
55 {
56 switch (type) {
57 RETURN_TEXT_FOR_CASE(Invalid);
58 RETURN_TEXT_FOR_CASE(UpdateAnnotations);
59 RETURN_TEXT_FOR_CASE(UpdateExtraAnnotations);
60 RETURN_TEXT_FOR_CASE(ParseSupportiveTranslationUnit);
61 RETURN_TEXT_FOR_CASE(RequestCompletions);
62 RETURN_TEXT_FOR_CASE(RequestAnnotations);
63 RETURN_TEXT_FOR_CASE(RequestReferences);
64 RETURN_TEXT_FOR_CASE(RequestFollowSymbol);
65 RETURN_TEXT_FOR_CASE(RequestToolTip);
66 RETURN_TEXT_FOR_CASE(SuspendDocument);
67 RETURN_TEXT_FOR_CASE(ResumeDocument);
68 }
69
70 return "UnhandledJobRequestType";
71 }
72 #undef RETURN_TEXT_FOR_CASE
73
74 #define RETURN_TEXT_FOR_CASE(enumValue) case PreferredTranslationUnit::enumValue: return #enumValue
preferredTranslationUnitToText(PreferredTranslationUnit type)75 const char *preferredTranslationUnitToText(PreferredTranslationUnit type)
76 {
77 switch (type) {
78 RETURN_TEXT_FOR_CASE(RecentlyParsed);
79 RETURN_TEXT_FOR_CASE(PreviouslyParsed);
80 RETURN_TEXT_FOR_CASE(LastUninitialized);
81 }
82
83 return "UnhandledPreferredTranslationUnitType";
84 }
85 #undef RETURN_TEXT_FOR_CASE
86
operator <<(QDebug debug,JobRequest::Type type)87 QDebug operator<<(QDebug debug, JobRequest::Type type)
88 {
89 debug << JobRequestTypeToText(type);
90
91 return debug;
92 }
93
operator <<(std::ostream & os,JobRequest::Type type)94 std::ostream &operator<<(std::ostream &os, JobRequest::Type type)
95 {
96 return os << JobRequestTypeToText(type);
97 }
98
operator <<(std::ostream & os,PreferredTranslationUnit preferredTranslationUnit)99 std::ostream &operator<<(std::ostream &os, PreferredTranslationUnit preferredTranslationUnit)
100 {
101 return os << preferredTranslationUnitToText(preferredTranslationUnit);
102 }
103
operator <<(QDebug debug,const JobRequest & jobRequest)104 QDebug operator<<(QDebug debug, const JobRequest &jobRequest)
105 {
106 debug.nospace() << "Job<"
107 << jobRequest.id
108 << ","
109 << QFileInfo(jobRequest.filePath).fileName()
110 << ","
111 << JobRequestTypeToText(jobRequest.type)
112 << ","
113 << preferredTranslationUnitToText(jobRequest.preferredTranslationUnit)
114 << ">";
115
116 return debug.space();
117 }
118
expirationConditionsForType(JobRequest::Type type)119 static JobRequest::ExpirationConditions expirationConditionsForType(JobRequest::Type type)
120 {
121 using Type = JobRequest::Type;
122 using Condition = JobRequest::ExpirationCondition;
123 using Conditions = JobRequest::ExpirationConditions;
124
125 switch (type) {
126 case Type::UpdateAnnotations:
127 case Type::UpdateExtraAnnotations:
128 return Conditions(Condition::AnythingChanged);
129 case Type::RequestReferences:
130 case Type::RequestAnnotations:
131 case Type::RequestToolTip:
132 case Type::RequestFollowSymbol:
133 return Conditions(Condition::DocumentClosed)
134 | Conditions(Condition::DocumentRevisionChanged);
135 default:
136 return Condition::DocumentClosed;
137 }
138 }
139
conditionsForType(JobRequest::Type type)140 static JobRequest::RunConditions conditionsForType(JobRequest::Type type)
141 {
142 using Type = JobRequest::Type;
143 using Condition = JobRequest::RunCondition;
144 using Conditions = JobRequest::RunConditions;
145
146 if (type == Type::SuspendDocument) {
147 return Conditions(Condition::DocumentUnsuspended)
148 | Conditions(Condition::DocumentNotVisible);
149 }
150
151 if (type == Type::ResumeDocument) {
152 return Conditions(Condition::DocumentSuspended)
153 | Conditions(Condition::DocumentVisible);
154 }
155
156 Conditions conditions = Conditions(Condition::DocumentUnsuspended)
157 | Conditions(Condition::DocumentVisible);
158
159 if (type == Type::RequestReferences || type == Type::RequestFollowSymbol
160 || type == Type::RequestToolTip || type == Type::UpdateExtraAnnotations) {
161 conditions |= Condition::CurrentDocumentRevision;
162 }
163
164 if (type != Type::UpdateAnnotations && type != Type::ParseSupportiveTranslationUnit)
165 conditions |= Condition::DocumentParsed;
166
167 return conditions;
168 }
169
isTakeOverable() const170 bool JobRequest::isTakeOverable() const
171 {
172 // When new project information comes in and there are unprocessed jobs
173 // in the queue, we need to decide what to do with them.
174
175 switch (type) {
176 // Never discard these as the client side might wait for a response.
177 case Type::RequestCompletions:
178 case Type::RequestReferences:
179 case Type::RequestFollowSymbol:
180 case Type::RequestToolTip:
181 return true;
182
183 // Discard this one as UpdateAnnotations will have the same effect.
184 case Type::RequestAnnotations:
185
186 // Discard Suspend because the document will be cleared anyway.
187 // Discard Resume because a (re)parse will happen on demand.
188 case Type::SuspendDocument:
189 case Type::ResumeDocument:
190
191 // Discard these as they are initial jobs that will be recreated on demand
192 // anyway.
193 case Type::UpdateAnnotations:
194 case Type::UpdateExtraAnnotations:
195
196 // Discard these as they only make sense in a row. Avoid splitting them up.
197 case Type::ParseSupportiveTranslationUnit:
198
199 case Type::Invalid:
200 return false;
201 }
202
203 return false;
204 }
205
JobRequest(Type type)206 JobRequest::JobRequest(Type type)
207 {
208 static quint64 idCounter = 0;
209
210 id = ++idCounter;
211 this->type = type;
212 runConditions = conditionsForType(type);
213 expirationConditions = expirationConditionsForType(type);
214 }
215
createJob() const216 IAsyncJob *JobRequest::createJob() const
217 {
218 switch (type) {
219 case JobRequest::Type::Invalid:
220 QTC_CHECK(false && "Cannot create job for invalid job request.");
221 break;
222 case JobRequest::Type::UpdateAnnotations:
223 return new UpdateAnnotationsJob();
224 case JobRequest::Type::UpdateExtraAnnotations:
225 return new UpdateExtraAnnotationsJob();
226 case JobRequest::Type::ParseSupportiveTranslationUnit:
227 return new ParseSupportiveTranslationUnitJob();
228 case JobRequest::Type::RequestCompletions:
229 return new CompleteCodeJob();
230 case JobRequest::Type::RequestAnnotations:
231 return new RequestAnnotationsJob();
232 case JobRequest::Type::RequestReferences:
233 return new RequestReferencesJob();
234 case JobRequest::Type::RequestToolTip:
235 return new RequestToolTipJob();
236 case JobRequest::Type::RequestFollowSymbol:
237 return new FollowSymbolJob();
238 case JobRequest::Type::SuspendDocument:
239 return new SuspendDocumentJob();
240 case JobRequest::Type::ResumeDocument:
241 return new ResumeDocumentJob();
242 }
243
244 return nullptr;
245 }
246
cancelJob(ClangCodeModelClientInterface & client) const247 void JobRequest::cancelJob(ClangCodeModelClientInterface &client) const
248 {
249 // If a job request with a ticket number is cancelled, the plugin side
250 // must get back some results in order to clean up the state there.
251
252 switch (type) {
253 case JobRequest::Type::Invalid:
254 case JobRequest::Type::UpdateAnnotations:
255 case JobRequest::Type::UpdateExtraAnnotations:
256 case JobRequest::Type::ParseSupportiveTranslationUnit:
257 case JobRequest::Type::RequestAnnotations:
258 case JobRequest::Type::SuspendDocument:
259 case JobRequest::Type::ResumeDocument:
260 break;
261 case JobRequest::Type::RequestReferences:
262 client.references(ReferencesMessage(FileContainer(),
263 QVector<SourceRangeContainer>(),
264 false,
265 ticketNumber));
266 break;
267 case JobRequest::Type::RequestToolTip:
268 client.tooltip(ToolTipMessage(FileContainer(), ToolTipInfo(), ticketNumber));
269 break;
270 case JobRequest::Type::RequestCompletions:
271 client.completions(CompletionsMessage(CodeCompletions(), ticketNumber));
272 break;
273 case JobRequest::Type::RequestFollowSymbol:
274 client.followSymbol(
275 FollowSymbolMessage(FileContainer(), SourceRangeContainer(), ticketNumber));
276 break;
277 }
278 }
279
operator ==(const JobRequest & other) const280 bool JobRequest::operator==(const JobRequest &other) const
281 {
282 return type == other.type
283 && expirationConditions == other.expirationConditions
284 && runConditions == other.runConditions
285
286 && filePath == other.filePath
287 && unsavedFilesChangeTimePoint == other.unsavedFilesChangeTimePoint
288 && documentRevision == other.documentRevision
289 && preferredTranslationUnit == other.preferredTranslationUnit
290
291 && line == other.line
292 && column == other.column
293 && ticketNumber == other.ticketNumber;
294
295 // Additional members that are not compared here explicitly are
296 // supposed to depend on the already compared ones.
297 }
298
299 } // namespace ClangBackEnd
300