Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(445)

Side by Side Diff: tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.cpp

Issue 1385193002: Bisect clang Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: 246985 Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "BlinkGCPluginConsumer.h"
6
7 #include <algorithm>
8 #include <set>
9
10 #include "CheckDispatchVisitor.h"
11 #include "CheckTraceVisitor.h"
12 #include "CollectVisitor.h"
13 #include "JsonWriter.h"
14 #include "RecordInfo.h"
15 #include "clang/AST/RecursiveASTVisitor.h"
16 #include "clang/Sema/Sema.h"
17
18 using namespace clang;
19
20 namespace {
21
22 const char kClassMustLeftMostlyDeriveGC[] =
23 "[blink-gc] Class %0 must derive its GC base in the left-most position.";
24
25 const char kClassRequiresTraceMethod[] =
26 "[blink-gc] Class %0 requires a trace method.";
27
28 const char kBaseRequiresTracing[] =
29 "[blink-gc] Base class %0 of derived class %1 requires tracing.";
30
31 const char kBaseRequiresTracingNote[] =
32 "[blink-gc] Untraced base class %0 declared here:";
33
34 const char kFieldsRequireTracing[] =
35 "[blink-gc] Class %0 has untraced fields that require tracing.";
36
37 const char kFieldRequiresTracingNote[] =
38 "[blink-gc] Untraced field %0 declared here:";
39
40 const char kClassContainsInvalidFields[] =
41 "[blink-gc] Class %0 contains invalid fields.";
42
43 const char kClassContainsGCRoot[] =
44 "[blink-gc] Class %0 contains GC root in field %1.";
45
46 const char kClassRequiresFinalization[] =
47 "[blink-gc] Class %0 requires finalization.";
48
49 const char kClassDoesNotRequireFinalization[] =
50 "[blink-gc] Class %0 may not require finalization.";
51
52 const char kFinalizerAccessesFinalizedField[] =
53 "[blink-gc] Finalizer %0 accesses potentially finalized field %1.";
54
55 const char kFinalizerAccessesEagerlyFinalizedField[] =
56 "[blink-gc] Finalizer %0 accesses eagerly finalized field %1.";
57
58 const char kRawPtrToGCManagedClassNote[] =
59 "[blink-gc] Raw pointer field %0 to a GC managed class declared here:";
60
61 const char kRefPtrToGCManagedClassNote[] =
62 "[blink-gc] RefPtr field %0 to a GC managed class declared here:";
63
64 const char kReferencePtrToGCManagedClassNote[] =
65 "[blink-gc] Reference pointer field %0 to a GC managed class"
66 " declared here:";
67
68 const char kOwnPtrToGCManagedClassNote[] =
69 "[blink-gc] OwnPtr field %0 to a GC managed class declared here:";
70
71 const char kMemberToGCUnmanagedClassNote[] =
72 "[blink-gc] Member field %0 to non-GC managed class declared here:";
73
74 const char kStackAllocatedFieldNote[] =
75 "[blink-gc] Stack-allocated field %0 declared here:";
76
77 const char kMemberInUnmanagedClassNote[] =
78 "[blink-gc] Member field %0 in unmanaged class declared here:";
79
80 const char kPartObjectToGCDerivedClassNote[] =
81 "[blink-gc] Part-object field %0 to a GC derived class declared here:";
82
83 const char kPartObjectContainsGCRootNote[] =
84 "[blink-gc] Field %0 with embedded GC root in %1 declared here:";
85
86 const char kFieldContainsGCRootNote[] =
87 "[blink-gc] Field %0 defining a GC root declared here:";
88
89 const char kOverriddenNonVirtualTrace[] =
90 "[blink-gc] Class %0 overrides non-virtual trace of base class %1.";
91
92 const char kOverriddenNonVirtualTraceNote[] =
93 "[blink-gc] Non-virtual trace method declared here:";
94
95 const char kMissingTraceDispatchMethod[] =
96 "[blink-gc] Class %0 is missing manual trace dispatch.";
97
98 const char kMissingFinalizeDispatchMethod[] =
99 "[blink-gc] Class %0 is missing manual finalize dispatch.";
100
101 const char kVirtualAndManualDispatch[] =
102 "[blink-gc] Class %0 contains or inherits virtual methods"
103 " but implements manual dispatching.";
104
105 const char kMissingTraceDispatch[] =
106 "[blink-gc] Missing dispatch to class %0 in manual trace dispatch.";
107
108 const char kMissingFinalizeDispatch[] =
109 "[blink-gc] Missing dispatch to class %0 in manual finalize dispatch.";
110
111 const char kFinalizedFieldNote[] =
112 "[blink-gc] Potentially finalized field %0 declared here:";
113
114 const char kEagerlyFinalizedFieldNote[] =
115 "[blink-gc] Field %0 having eagerly finalized value, declared here:";
116
117 const char kUserDeclaredDestructorNote[] =
118 "[blink-gc] User-declared destructor declared here:";
119
120 const char kUserDeclaredFinalizerNote[] =
121 "[blink-gc] User-declared finalizer declared here:";
122
123 const char kBaseRequiresFinalizationNote[] =
124 "[blink-gc] Base class %0 requiring finalization declared here:";
125
126 const char kFieldRequiresFinalizationNote[] =
127 "[blink-gc] Field %0 requiring finalization declared here:";
128
129 const char kManualDispatchMethodNote[] =
130 "[blink-gc] Manual dispatch %0 declared here:";
131
132 const char kDerivesNonStackAllocated[] =
133 "[blink-gc] Stack-allocated class %0 derives class %1"
134 " which is not stack allocated.";
135
136 const char kClassOverridesNew[] =
137 "[blink-gc] Garbage collected class %0"
138 " is not permitted to override its new operator.";
139
140 const char kClassDeclaresPureVirtualTrace[] =
141 "[blink-gc] Garbage collected class %0"
142 " is not permitted to declare a pure-virtual trace method.";
143
144 const char kLeftMostBaseMustBePolymorphic[] =
145 "[blink-gc] Left-most base class %0 of derived class %1"
146 " must be polymorphic.";
147
148 const char kBaseClassMustDeclareVirtualTrace[] =
149 "[blink-gc] Left-most base class %0 of derived class %1"
150 " must define a virtual trace method.";
151
152 const char kClassMustDeclareGCMixinTraceMethod[] =
153 "[blink-gc] Class %0 which inherits from GarbageCollectedMixin must"
154 " locally declare and override trace(Visitor*)";
155
156 // Use a local RAV implementation to simply collect all FunctionDecls marked for
157 // late template parsing. This happens with the flag -fdelayed-template-parsing,
158 // which is on by default in MSVC-compatible mode.
159 std::set<FunctionDecl*> GetLateParsedFunctionDecls(TranslationUnitDecl* decl) {
160 struct Visitor : public RecursiveASTVisitor<Visitor> {
161 bool VisitFunctionDecl(FunctionDecl* function_decl) {
162 if (function_decl->isLateTemplateParsed())
163 late_parsed_decls.insert(function_decl);
164 return true;
165 }
166
167 std::set<FunctionDecl*> late_parsed_decls;
168 } v;
169 v.TraverseDecl(decl);
170 return v.late_parsed_decls;
171 }
172
173 class EmptyStmtVisitor : public RecursiveASTVisitor<EmptyStmtVisitor> {
174 public:
175 static bool isEmpty(Stmt* stmt) {
176 EmptyStmtVisitor visitor;
177 visitor.TraverseStmt(stmt);
178 return visitor.empty_;
179 }
180
181 bool WalkUpFromCompoundStmt(CompoundStmt* stmt) {
182 empty_ = stmt->body_empty();
183 return false;
184 }
185 bool VisitStmt(Stmt*) {
186 empty_ = false;
187 return false;
188 }
189 private:
190 EmptyStmtVisitor() : empty_(true) {}
191 bool empty_;
192 };
193
194 } // namespace
195
196 BlinkGCPluginConsumer::BlinkGCPluginConsumer(
197 clang::CompilerInstance& instance,
198 const BlinkGCPluginOptions& options)
199 : instance_(instance),
200 diagnostic_(instance.getDiagnostics()),
201 options_(options),
202 json_(0) {
203 // Only check structures in the blink and WebKit namespaces.
204 options_.checked_namespaces.insert("blink");
205
206 // Ignore GC implementation files.
207 options_.ignored_directories.push_back("/heap/");
208
209 // Register warning/error messages.
210 diag_class_must_left_mostly_derive_gc_ = diagnostic_.getCustomDiagID(
211 getErrorLevel(), kClassMustLeftMostlyDeriveGC);
212 diag_class_requires_trace_method_ =
213 diagnostic_.getCustomDiagID(getErrorLevel(), kClassRequiresTraceMethod);
214 diag_base_requires_tracing_ =
215 diagnostic_.getCustomDiagID(getErrorLevel(), kBaseRequiresTracing);
216 diag_fields_require_tracing_ =
217 diagnostic_.getCustomDiagID(getErrorLevel(), kFieldsRequireTracing);
218 diag_class_contains_invalid_fields_ = diagnostic_.getCustomDiagID(
219 getErrorLevel(), kClassContainsInvalidFields);
220 diag_class_contains_invalid_fields_warning_ = diagnostic_.getCustomDiagID(
221 DiagnosticsEngine::Warning, kClassContainsInvalidFields);
222 diag_class_contains_gc_root_ =
223 diagnostic_.getCustomDiagID(getErrorLevel(), kClassContainsGCRoot);
224 diag_class_requires_finalization_ = diagnostic_.getCustomDiagID(
225 getErrorLevel(), kClassRequiresFinalization);
226 diag_class_does_not_require_finalization_ = diagnostic_.getCustomDiagID(
227 DiagnosticsEngine::Warning, kClassDoesNotRequireFinalization);
228 diag_finalizer_accesses_finalized_field_ = diagnostic_.getCustomDiagID(
229 getErrorLevel(), kFinalizerAccessesFinalizedField);
230 diag_finalizer_eagerly_finalized_field_ = diagnostic_.getCustomDiagID(
231 getErrorLevel(), kFinalizerAccessesEagerlyFinalizedField);
232 diag_overridden_non_virtual_trace_ = diagnostic_.getCustomDiagID(
233 getErrorLevel(), kOverriddenNonVirtualTrace);
234 diag_missing_trace_dispatch_method_ = diagnostic_.getCustomDiagID(
235 getErrorLevel(), kMissingTraceDispatchMethod);
236 diag_missing_finalize_dispatch_method_ = diagnostic_.getCustomDiagID(
237 getErrorLevel(), kMissingFinalizeDispatchMethod);
238 diag_virtual_and_manual_dispatch_ =
239 diagnostic_.getCustomDiagID(getErrorLevel(), kVirtualAndManualDispatch);
240 diag_missing_trace_dispatch_ =
241 diagnostic_.getCustomDiagID(getErrorLevel(), kMissingTraceDispatch);
242 diag_missing_finalize_dispatch_ =
243 diagnostic_.getCustomDiagID(getErrorLevel(), kMissingFinalizeDispatch);
244 diag_derives_non_stack_allocated_ =
245 diagnostic_.getCustomDiagID(getErrorLevel(), kDerivesNonStackAllocated);
246 diag_class_overrides_new_ =
247 diagnostic_.getCustomDiagID(getErrorLevel(), kClassOverridesNew);
248 diag_class_declares_pure_virtual_trace_ = diagnostic_.getCustomDiagID(
249 getErrorLevel(), kClassDeclaresPureVirtualTrace);
250 diag_left_most_base_must_be_polymorphic_ = diagnostic_.getCustomDiagID(
251 getErrorLevel(), kLeftMostBaseMustBePolymorphic);
252 diag_base_class_must_declare_virtual_trace_ = diagnostic_.getCustomDiagID(
253 getErrorLevel(), kBaseClassMustDeclareVirtualTrace);
254 diag_class_must_declare_gc_mixin_trace_method_ =
255 diagnostic_.getCustomDiagID(getErrorLevel(),
256 kClassMustDeclareGCMixinTraceMethod);
257
258 // Register note messages.
259 diag_base_requires_tracing_note_ = diagnostic_.getCustomDiagID(
260 DiagnosticsEngine::Note, kBaseRequiresTracingNote);
261 diag_field_requires_tracing_note_ = diagnostic_.getCustomDiagID(
262 DiagnosticsEngine::Note, kFieldRequiresTracingNote);
263 diag_raw_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
264 DiagnosticsEngine::Note, kRawPtrToGCManagedClassNote);
265 diag_ref_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
266 DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote);
267 diag_reference_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
268 DiagnosticsEngine::Note, kReferencePtrToGCManagedClassNote);
269 diag_own_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
270 DiagnosticsEngine::Note, kOwnPtrToGCManagedClassNote);
271 diag_member_to_gc_unmanaged_class_note_ = diagnostic_.getCustomDiagID(
272 DiagnosticsEngine::Note, kMemberToGCUnmanagedClassNote);
273 diag_stack_allocated_field_note_ = diagnostic_.getCustomDiagID(
274 DiagnosticsEngine::Note, kStackAllocatedFieldNote);
275 diag_member_in_unmanaged_class_note_ = diagnostic_.getCustomDiagID(
276 DiagnosticsEngine::Note, kMemberInUnmanagedClassNote);
277 diag_part_object_to_gc_derived_class_note_ = diagnostic_.getCustomDiagID(
278 DiagnosticsEngine::Note, kPartObjectToGCDerivedClassNote);
279 diag_part_object_contains_gc_root_note_ = diagnostic_.getCustomDiagID(
280 DiagnosticsEngine::Note, kPartObjectContainsGCRootNote);
281 diag_field_contains_gc_root_note_ = diagnostic_.getCustomDiagID(
282 DiagnosticsEngine::Note, kFieldContainsGCRootNote);
283 diag_finalized_field_note_ = diagnostic_.getCustomDiagID(
284 DiagnosticsEngine::Note, kFinalizedFieldNote);
285 diag_eagerly_finalized_field_note_ = diagnostic_.getCustomDiagID(
286 DiagnosticsEngine::Note, kEagerlyFinalizedFieldNote);
287 diag_user_declared_destructor_note_ = diagnostic_.getCustomDiagID(
288 DiagnosticsEngine::Note, kUserDeclaredDestructorNote);
289 diag_user_declared_finalizer_note_ = diagnostic_.getCustomDiagID(
290 DiagnosticsEngine::Note, kUserDeclaredFinalizerNote);
291 diag_base_requires_finalization_note_ = diagnostic_.getCustomDiagID(
292 DiagnosticsEngine::Note, kBaseRequiresFinalizationNote);
293 diag_field_requires_finalization_note_ = diagnostic_.getCustomDiagID(
294 DiagnosticsEngine::Note, kFieldRequiresFinalizationNote);
295 diag_overridden_non_virtual_trace_note_ = diagnostic_.getCustomDiagID(
296 DiagnosticsEngine::Note, kOverriddenNonVirtualTraceNote);
297 diag_manual_dispatch_method_note_ = diagnostic_.getCustomDiagID(
298 DiagnosticsEngine::Note, kManualDispatchMethodNote);
299 }
300
301 void BlinkGCPluginConsumer::HandleTranslationUnit(ASTContext& context) {
302 // Don't run the plugin if the compilation unit is already invalid.
303 if (diagnostic_.hasErrorOccurred())
304 return;
305
306 ParseFunctionTemplates(context.getTranslationUnitDecl());
307
308 CollectVisitor visitor;
309 visitor.TraverseDecl(context.getTranslationUnitDecl());
310
311 if (options_.dump_graph) {
312 std::error_code err;
313 // TODO: Make createDefaultOutputFile or a shorter createOutputFile work.
314 json_ = JsonWriter::from(instance_.createOutputFile(
315 "", // OutputPath
316 err, // Errors
317 true, // Binary
318 true, // RemoveFileOnSignal
319 instance_.getFrontendOpts().OutputFile, // BaseInput
320 "graph.json", // Extension
321 false, // UseTemporary
322 false, // CreateMissingDirectories
323 0, // ResultPathName
324 0)); // TempPathName
325 if (!err && json_) {
326 json_->OpenList();
327 } else {
328 json_ = 0;
329 llvm::errs()
330 << "[blink-gc] "
331 << "Failed to create an output file for the object graph.\n";
332 }
333 }
334
335 for (CollectVisitor::RecordVector::iterator it =
336 visitor.record_decls().begin();
337 it != visitor.record_decls().end();
338 ++it) {
339 CheckRecord(cache_.Lookup(*it));
340 }
341
342 for (CollectVisitor::MethodVector::iterator it =
343 visitor.trace_decls().begin();
344 it != visitor.trace_decls().end();
345 ++it) {
346 CheckTracingMethod(*it);
347 }
348
349 if (json_) {
350 json_->CloseList();
351 delete json_;
352 json_ = 0;
353 }
354 }
355
356 void BlinkGCPluginConsumer::ParseFunctionTemplates(TranslationUnitDecl* decl) {
357 if (!instance_.getLangOpts().DelayedTemplateParsing)
358 return; // Nothing to do.
359
360 std::set<FunctionDecl*> late_parsed_decls = GetLateParsedFunctionDecls(decl);
361 clang::Sema& sema = instance_.getSema();
362
363 for (const FunctionDecl* fd : late_parsed_decls) {
364 assert(fd->isLateTemplateParsed());
365
366 if (!Config::IsTraceMethod(fd))
367 continue;
368
369 if (instance_.getSourceManager().isInSystemHeader(
370 instance_.getSourceManager().getSpellingLoc(fd->getLocation())))
371 continue;
372
373 // Force parsing and AST building of the yet-uninstantiated function
374 // template trace method bodies.
375 clang::LateParsedTemplate* lpt = sema.LateParsedTemplateMap[fd];
376 sema.LateTemplateParser(sema.OpaqueParser, *lpt);
377 }
378 }
379
380 void BlinkGCPluginConsumer::CheckRecord(RecordInfo* info) {
381 if (IsIgnored(info))
382 return;
383
384 CXXRecordDecl* record = info->record();
385
386 // TODO: what should we do to check unions?
387 if (record->isUnion())
388 return;
389
390 // If this is the primary template declaration, check its specializations.
391 if (record->isThisDeclarationADefinition() &&
392 record->getDescribedClassTemplate()) {
393 ClassTemplateDecl* tmpl = record->getDescribedClassTemplate();
394 for (ClassTemplateDecl::spec_iterator it = tmpl->spec_begin();
395 it != tmpl->spec_end();
396 ++it) {
397 CheckClass(cache_.Lookup(*it));
398 }
399 return;
400 }
401
402 CheckClass(info);
403 }
404
405 void BlinkGCPluginConsumer::CheckClass(RecordInfo* info) {
406 if (!info)
407 return;
408
409 // Check consistency of stack-allocated hierarchies.
410 if (info->IsStackAllocated()) {
411 for (RecordInfo::Bases::iterator it = info->GetBases().begin();
412 it != info->GetBases().end();
413 ++it) {
414 if (!it->second.info()->IsStackAllocated())
415 ReportDerivesNonStackAllocated(info, &it->second);
416 }
417 }
418
419 if (CXXMethodDecl* trace = info->GetTraceMethod()) {
420 if (trace->isPure())
421 ReportClassDeclaresPureVirtualTrace(info, trace);
422 } else if (info->RequiresTraceMethod()) {
423 ReportClassRequiresTraceMethod(info);
424 }
425
426 // Check polymorphic classes that are GC-derived or have a trace method.
427 if (info->record()->hasDefinition() && info->record()->isPolymorphic()) {
428 // TODO: Check classes that inherit a trace method.
429 CXXMethodDecl* trace = info->GetTraceMethod();
430 if (trace || info->IsGCDerived())
431 CheckPolymorphicClass(info, trace);
432 }
433
434 {
435 CheckFieldsVisitor visitor(options_);
436 if (visitor.ContainsInvalidFields(info))
437 ReportClassContainsInvalidFields(info, &visitor.invalid_fields());
438 }
439
440 if (info->IsGCDerived()) {
441 if (!info->IsGCMixin()) {
442 CheckLeftMostDerived(info);
443 CheckDispatch(info);
444 if (CXXMethodDecl* newop = info->DeclaresNewOperator())
445 if (!Config::IsIgnoreAnnotated(newop))
446 ReportClassOverridesNew(info, newop);
447 if (info->IsGCMixinInstance()) {
448 // Require that declared GCMixin implementations
449 // also provide a trace() override.
450 if (info->DeclaresGCMixinMethods()
451 && !info->DeclaresLocalTraceMethod())
452 ReportClassMustDeclareGCMixinTraceMethod(info);
453 }
454 }
455
456 {
457 CheckGCRootsVisitor visitor;
458 if (visitor.ContainsGCRoots(info))
459 ReportClassContainsGCRoots(info, &visitor.gc_roots());
460 }
461
462 if (info->NeedsFinalization())
463 CheckFinalization(info);
464
465 if (options_.warn_unneeded_finalizer && info->IsGCFinalized())
466 CheckUnneededFinalization(info);
467 }
468
469 DumpClass(info);
470 }
471
472 CXXRecordDecl* BlinkGCPluginConsumer::GetDependentTemplatedDecl(
473 const Type& type) {
474 const TemplateSpecializationType* tmpl_type =
475 type.getAs<TemplateSpecializationType>();
476 if (!tmpl_type)
477 return 0;
478
479 TemplateDecl* tmpl_decl = tmpl_type->getTemplateName().getAsTemplateDecl();
480 if (!tmpl_decl)
481 return 0;
482
483 return dyn_cast<CXXRecordDecl>(tmpl_decl->getTemplatedDecl());
484 }
485
486 // The GC infrastructure assumes that if the vtable of a polymorphic
487 // base-class is not initialized for a given object (ie, it is partially
488 // initialized) then the object does not need to be traced. Thus, we must
489 // ensure that any polymorphic class with a trace method does not have any
490 // tractable fields that are initialized before we are sure that the vtable
491 // and the trace method are both defined. There are two cases that need to
492 // hold to satisfy that assumption:
493 //
494 // 1. If trace is virtual, then it must be defined in the left-most base.
495 // This ensures that if the vtable is initialized then it contains a pointer
496 // to the trace method.
497 //
498 // 2. If trace is non-virtual, then the trace method is defined and we must
499 // ensure that the left-most base defines a vtable. This ensures that the
500 // first thing to be initialized when constructing the object is the vtable
501 // itself.
502 void BlinkGCPluginConsumer::CheckPolymorphicClass(
503 RecordInfo* info,
504 CXXMethodDecl* trace) {
505 CXXRecordDecl* left_most = info->record();
506 CXXRecordDecl::base_class_iterator it = left_most->bases_begin();
507 CXXRecordDecl* left_most_base = 0;
508 while (it != left_most->bases_end()) {
509 left_most_base = it->getType()->getAsCXXRecordDecl();
510 if (!left_most_base && it->getType()->isDependentType())
511 left_most_base = RecordInfo::GetDependentTemplatedDecl(*it->getType());
512
513 // TODO: Find a way to correctly check actual instantiations
514 // for dependent types. The escape below will be hit, eg, when
515 // we have a primary template with no definition and
516 // specializations for each case (such as SupplementBase) in
517 // which case we don't succeed in checking the required
518 // properties.
519 if (!left_most_base || !left_most_base->hasDefinition())
520 return;
521
522 StringRef name = left_most_base->getName();
523 // We know GCMixin base defines virtual trace.
524 if (Config::IsGCMixinBase(name))
525 return;
526
527 // Stop with the left-most prior to a safe polymorphic base (a safe base
528 // is non-polymorphic and contains no fields).
529 if (Config::IsSafePolymorphicBase(name))
530 break;
531
532 left_most = left_most_base;
533 it = left_most->bases_begin();
534 }
535
536 if (RecordInfo* left_most_info = cache_.Lookup(left_most)) {
537 // Check condition (1):
538 if (trace && trace->isVirtual()) {
539 if (CXXMethodDecl* trace = left_most_info->GetTraceMethod()) {
540 if (trace->isVirtual())
541 return;
542 }
543 ReportBaseClassMustDeclareVirtualTrace(info, left_most);
544 return;
545 }
546
547 // Check condition (2):
548 if (DeclaresVirtualMethods(left_most))
549 return;
550 if (left_most_base) {
551 // Get the base next to the "safe polymorphic base"
552 if (it != left_most->bases_end())
553 ++it;
554 if (it != left_most->bases_end()) {
555 if (CXXRecordDecl* next_base = it->getType()->getAsCXXRecordDecl()) {
556 if (CXXRecordDecl* next_left_most = GetLeftMostBase(next_base)) {
557 if (DeclaresVirtualMethods(next_left_most))
558 return;
559 ReportLeftMostBaseMustBePolymorphic(info, next_left_most);
560 return;
561 }
562 }
563 }
564 }
565 ReportLeftMostBaseMustBePolymorphic(info, left_most);
566 }
567 }
568
569 CXXRecordDecl* BlinkGCPluginConsumer::GetLeftMostBase(
570 CXXRecordDecl* left_most) {
571 CXXRecordDecl::base_class_iterator it = left_most->bases_begin();
572 while (it != left_most->bases_end()) {
573 if (it->getType()->isDependentType())
574 left_most = RecordInfo::GetDependentTemplatedDecl(*it->getType());
575 else
576 left_most = it->getType()->getAsCXXRecordDecl();
577 if (!left_most || !left_most->hasDefinition())
578 return 0;
579 it = left_most->bases_begin();
580 }
581 return left_most;
582 }
583
584 bool BlinkGCPluginConsumer::DeclaresVirtualMethods(CXXRecordDecl* decl) {
585 CXXRecordDecl::method_iterator it = decl->method_begin();
586 for (; it != decl->method_end(); ++it)
587 if (it->isVirtual() && !it->isPure())
588 return true;
589 return false;
590 }
591
592 void BlinkGCPluginConsumer::CheckLeftMostDerived(RecordInfo* info) {
593 CXXRecordDecl* left_most = GetLeftMostBase(info->record());
594 if (!left_most)
595 return;
596 if (!Config::IsGCBase(left_most->getName()))
597 ReportClassMustLeftMostlyDeriveGC(info);
598 }
599
600 void BlinkGCPluginConsumer::CheckDispatch(RecordInfo* info) {
601 bool finalized = info->IsGCFinalized();
602 CXXMethodDecl* trace_dispatch = info->GetTraceDispatchMethod();
603 CXXMethodDecl* finalize_dispatch = info->GetFinalizeDispatchMethod();
604 if (!trace_dispatch && !finalize_dispatch)
605 return;
606
607 CXXRecordDecl* base = trace_dispatch ? trace_dispatch->getParent()
608 : finalize_dispatch->getParent();
609
610 // Check that dispatch methods are defined at the base.
611 if (base == info->record()) {
612 if (!trace_dispatch)
613 ReportMissingTraceDispatchMethod(info);
614 if (finalized && !finalize_dispatch)
615 ReportMissingFinalizeDispatchMethod(info);
616 if (!finalized && finalize_dispatch) {
617 ReportClassRequiresFinalization(info);
618 NoteUserDeclaredFinalizer(finalize_dispatch);
619 }
620 }
621
622 // Check that classes implementing manual dispatch do not have vtables.
623 if (info->record()->isPolymorphic()) {
624 ReportVirtualAndManualDispatch(
625 info, trace_dispatch ? trace_dispatch : finalize_dispatch);
626 }
627
628 // If this is a non-abstract class check that it is dispatched to.
629 // TODO: Create a global variant of this local check. We can only check if
630 // the dispatch body is known in this compilation unit.
631 if (info->IsConsideredAbstract())
632 return;
633
634 const FunctionDecl* defn;
635
636 if (trace_dispatch && trace_dispatch->isDefined(defn)) {
637 CheckDispatchVisitor visitor(info);
638 visitor.TraverseStmt(defn->getBody());
639 if (!visitor.dispatched_to_receiver())
640 ReportMissingTraceDispatch(defn, info);
641 }
642
643 if (finalized && finalize_dispatch && finalize_dispatch->isDefined(defn)) {
644 CheckDispatchVisitor visitor(info);
645 visitor.TraverseStmt(defn->getBody());
646 if (!visitor.dispatched_to_receiver())
647 ReportMissingFinalizeDispatch(defn, info);
648 }
649 }
650
651 // TODO: Should we collect destructors similar to trace methods?
652 void BlinkGCPluginConsumer::CheckFinalization(RecordInfo* info) {
653 CXXDestructorDecl* dtor = info->record()->getDestructor();
654
655 // For finalized classes, check the finalization method if possible.
656 if (info->IsGCFinalized()) {
657 if (dtor && dtor->hasBody()) {
658 CheckFinalizerVisitor visitor(&cache_, info->IsEagerlyFinalized());
659 visitor.TraverseCXXMethodDecl(dtor);
660 if (!visitor.finalized_fields().empty()) {
661 ReportFinalizerAccessesFinalizedFields(
662 dtor, &visitor.finalized_fields());
663 }
664 }
665 return;
666 }
667
668 // Don't require finalization of a mixin that has not yet been "mixed in".
669 if (info->IsGCMixin())
670 return;
671
672 // Report the finalization error, and proceed to print possible causes for
673 // the finalization requirement.
674 ReportClassRequiresFinalization(info);
675
676 if (dtor && dtor->isUserProvided())
677 NoteUserDeclaredDestructor(dtor);
678
679 for (RecordInfo::Bases::iterator it = info->GetBases().begin();
680 it != info->GetBases().end();
681 ++it) {
682 if (it->second.info()->NeedsFinalization())
683 NoteBaseRequiresFinalization(&it->second);
684 }
685
686 for (RecordInfo::Fields::iterator it = info->GetFields().begin();
687 it != info->GetFields().end();
688 ++it) {
689 if (it->second.edge()->NeedsFinalization())
690 NoteField(&it->second, diag_field_requires_finalization_note_);
691 }
692 }
693
694 void BlinkGCPluginConsumer::CheckUnneededFinalization(RecordInfo* info) {
695 if (!HasNonEmptyFinalizer(info))
696 ReportClassDoesNotRequireFinalization(info);
697 }
698
699 bool BlinkGCPluginConsumer::HasNonEmptyFinalizer(RecordInfo* info) {
700 CXXDestructorDecl* dtor = info->record()->getDestructor();
701 if (dtor && dtor->isUserProvided()) {
702 if (!dtor->hasBody() || !EmptyStmtVisitor::isEmpty(dtor->getBody()))
703 return true;
704 }
705 for (RecordInfo::Bases::iterator it = info->GetBases().begin();
706 it != info->GetBases().end();
707 ++it) {
708 if (HasNonEmptyFinalizer(it->second.info()))
709 return true;
710 }
711 for (RecordInfo::Fields::iterator it = info->GetFields().begin();
712 it != info->GetFields().end();
713 ++it) {
714 if (it->second.edge()->NeedsFinalization())
715 return true;
716 }
717 return false;
718 }
719
720 void BlinkGCPluginConsumer::CheckTracingMethod(CXXMethodDecl* method) {
721 RecordInfo* parent = cache_.Lookup(method->getParent());
722 if (IsIgnored(parent))
723 return;
724
725 // Check templated tracing methods by checking the template instantiations.
726 // Specialized templates are handled as ordinary classes.
727 if (ClassTemplateDecl* tmpl =
728 parent->record()->getDescribedClassTemplate()) {
729 for (ClassTemplateDecl::spec_iterator it = tmpl->spec_begin();
730 it != tmpl->spec_end();
731 ++it) {
732 // Check trace using each template instantiation as the holder.
733 if (Config::IsTemplateInstantiation(*it))
734 CheckTraceOrDispatchMethod(cache_.Lookup(*it), method);
735 }
736 return;
737 }
738
739 CheckTraceOrDispatchMethod(parent, method);
740 }
741
742 void BlinkGCPluginConsumer::CheckTraceOrDispatchMethod(
743 RecordInfo* parent,
744 CXXMethodDecl* method) {
745 Config::TraceMethodType trace_type = Config::GetTraceMethodType(method);
746 if (trace_type == Config::TRACE_AFTER_DISPATCH_METHOD ||
747 trace_type == Config::TRACE_AFTER_DISPATCH_IMPL_METHOD ||
748 !parent->GetTraceDispatchMethod()) {
749 CheckTraceMethod(parent, method, trace_type);
750 }
751 // Dispatch methods are checked when we identify subclasses.
752 }
753
754 void BlinkGCPluginConsumer::CheckTraceMethod(
755 RecordInfo* parent,
756 CXXMethodDecl* trace,
757 Config::TraceMethodType trace_type) {
758 // A trace method must not override any non-virtual trace methods.
759 if (trace_type == Config::TRACE_METHOD) {
760 for (RecordInfo::Bases::iterator it = parent->GetBases().begin();
761 it != parent->GetBases().end();
762 ++it) {
763 RecordInfo* base = it->second.info();
764 if (CXXMethodDecl* other = base->InheritsNonVirtualTrace())
765 ReportOverriddenNonVirtualTrace(parent, trace, other);
766 }
767 }
768
769 CheckTraceVisitor visitor(trace, parent, &cache_);
770 visitor.TraverseCXXMethodDecl(trace);
771
772 // Skip reporting if this trace method is a just delegate to
773 // traceImpl (or traceAfterDispatchImpl) method. We will report on
774 // CheckTraceMethod on traceImpl method.
775 if (visitor.delegates_to_traceimpl())
776 return;
777
778 for (RecordInfo::Bases::iterator it = parent->GetBases().begin();
779 it != parent->GetBases().end();
780 ++it) {
781 if (!it->second.IsProperlyTraced())
782 ReportBaseRequiresTracing(parent, trace, it->first);
783 }
784
785 for (RecordInfo::Fields::iterator it = parent->GetFields().begin();
786 it != parent->GetFields().end();
787 ++it) {
788 if (!it->second.IsProperlyTraced()) {
789 // Discontinue once an untraced-field error is found.
790 ReportFieldsRequireTracing(parent, trace);
791 break;
792 }
793 }
794 }
795
796 void BlinkGCPluginConsumer::DumpClass(RecordInfo* info) {
797 if (!json_)
798 return;
799
800 json_->OpenObject();
801 json_->Write("name", info->record()->getQualifiedNameAsString());
802 json_->Write("loc", GetLocString(info->record()->getLocStart()));
803 json_->CloseObject();
804
805 class DumpEdgeVisitor : public RecursiveEdgeVisitor {
806 public:
807 DumpEdgeVisitor(JsonWriter* json) : json_(json) {}
808 void DumpEdge(RecordInfo* src,
809 RecordInfo* dst,
810 const std::string& lbl,
811 const Edge::LivenessKind& kind,
812 const std::string& loc) {
813 json_->OpenObject();
814 json_->Write("src", src->record()->getQualifiedNameAsString());
815 json_->Write("dst", dst->record()->getQualifiedNameAsString());
816 json_->Write("lbl", lbl);
817 json_->Write("kind", kind);
818 json_->Write("loc", loc);
819 json_->Write("ptr",
820 !Parent() ? "val" :
821 Parent()->IsRawPtr() ?
822 (static_cast<RawPtr*>(Parent())->HasReferenceType() ?
823 "reference" : "raw") :
824 Parent()->IsRefPtr() ? "ref" :
825 Parent()->IsOwnPtr() ? "own" :
826 (Parent()->IsMember() || Parent()->IsWeakMember()) ? "mem" :
827 "val");
828 json_->CloseObject();
829 }
830
831 void DumpField(RecordInfo* src, FieldPoint* point, const std::string& loc) {
832 src_ = src;
833 point_ = point;
834 loc_ = loc;
835 point_->edge()->Accept(this);
836 }
837
838 void AtValue(Value* e) override {
839 // The liveness kind of a path from the point to this value
840 // is given by the innermost place that is non-strong.
841 Edge::LivenessKind kind = Edge::kStrong;
842 if (Config::IsIgnoreCycleAnnotated(point_->field())) {
843 kind = Edge::kWeak;
844 } else {
845 for (Context::iterator it = context().begin();
846 it != context().end();
847 ++it) {
848 Edge::LivenessKind pointer_kind = (*it)->Kind();
849 if (pointer_kind != Edge::kStrong) {
850 kind = pointer_kind;
851 break;
852 }
853 }
854 }
855 DumpEdge(
856 src_, e->value(), point_->field()->getNameAsString(), kind, loc_);
857 }
858
859 private:
860 JsonWriter* json_;
861 RecordInfo* src_;
862 FieldPoint* point_;
863 std::string loc_;
864 };
865
866 DumpEdgeVisitor visitor(json_);
867
868 RecordInfo::Bases& bases = info->GetBases();
869 for (RecordInfo::Bases::iterator it = bases.begin();
870 it != bases.end();
871 ++it) {
872 visitor.DumpEdge(info,
873 it->second.info(),
874 "<super>",
875 Edge::kStrong,
876 GetLocString(it->second.spec().getLocStart()));
877 }
878
879 RecordInfo::Fields& fields = info->GetFields();
880 for (RecordInfo::Fields::iterator it = fields.begin();
881 it != fields.end();
882 ++it) {
883 visitor.DumpField(info,
884 &it->second,
885 GetLocString(it->second.field()->getLocStart()));
886 }
887 }
888
889 DiagnosticsEngine::Level BlinkGCPluginConsumer::getErrorLevel() {
890 return diagnostic_.getWarningsAsErrors() ? DiagnosticsEngine::Error
891 : DiagnosticsEngine::Warning;
892 }
893
894 std::string BlinkGCPluginConsumer::GetLocString(SourceLocation loc) {
895 const SourceManager& source_manager = instance_.getSourceManager();
896 PresumedLoc ploc = source_manager.getPresumedLoc(loc);
897 if (ploc.isInvalid())
898 return "";
899 std::string loc_str;
900 llvm::raw_string_ostream os(loc_str);
901 os << ploc.getFilename()
902 << ":" << ploc.getLine()
903 << ":" << ploc.getColumn();
904 return os.str();
905 }
906
907 bool BlinkGCPluginConsumer::IsIgnored(RecordInfo* record) {
908 return (!record ||
909 !InCheckedNamespace(record) ||
910 IsIgnoredClass(record) ||
911 InIgnoredDirectory(record));
912 }
913
914 bool BlinkGCPluginConsumer::IsIgnoredClass(RecordInfo* info) {
915 // Ignore any class prefixed by SameSizeAs. These are used in
916 // Blink to verify class sizes and don't need checking.
917 const std::string SameSizeAs = "SameSizeAs";
918 if (info->name().compare(0, SameSizeAs.size(), SameSizeAs) == 0)
919 return true;
920 return (options_.ignored_classes.find(info->name()) !=
921 options_.ignored_classes.end());
922 }
923
924 bool BlinkGCPluginConsumer::InIgnoredDirectory(RecordInfo* info) {
925 std::string filename;
926 if (!GetFilename(info->record()->getLocStart(), &filename))
927 return false; // TODO: should we ignore non-existing file locations?
928 #if defined(LLVM_ON_WIN32)
929 std::replace(filename.begin(), filename.end(), '\\', '/');
930 #endif
931 std::vector<std::string>::iterator it = options_.ignored_directories.begin();
932 for (; it != options_.ignored_directories.end(); ++it)
933 if (filename.find(*it) != std::string::npos)
934 return true;
935 return false;
936 }
937
938 bool BlinkGCPluginConsumer::InCheckedNamespace(RecordInfo* info) {
939 if (!info)
940 return false;
941 for (DeclContext* context = info->record()->getDeclContext();
942 !context->isTranslationUnit();
943 context = context->getParent()) {
944 if (NamespaceDecl* decl = dyn_cast<NamespaceDecl>(context)) {
945 if (decl->isAnonymousNamespace())
946 return true;
947 if (options_.checked_namespaces.find(decl->getNameAsString()) !=
948 options_.checked_namespaces.end()) {
949 return true;
950 }
951 }
952 }
953 return false;
954 }
955
956 bool BlinkGCPluginConsumer::GetFilename(SourceLocation loc,
957 std::string* filename) {
958 const SourceManager& source_manager = instance_.getSourceManager();
959 SourceLocation spelling_location = source_manager.getSpellingLoc(loc);
960 PresumedLoc ploc = source_manager.getPresumedLoc(spelling_location);
961 if (ploc.isInvalid()) {
962 // If we're in an invalid location, we're looking at things that aren't
963 // actually stated in the source.
964 return false;
965 }
966 *filename = ploc.getFilename();
967 return true;
968 }
969
970 void BlinkGCPluginConsumer::ReportClassMustLeftMostlyDeriveGC(
971 RecordInfo* info) {
972 SourceLocation loc = info->record()->getInnerLocStart();
973 SourceManager& manager = instance_.getSourceManager();
974 FullSourceLoc full_loc(loc, manager);
975 diagnostic_.Report(full_loc, diag_class_must_left_mostly_derive_gc_)
976 << info->record();
977 }
978
979 void BlinkGCPluginConsumer::ReportClassRequiresTraceMethod(RecordInfo* info) {
980 SourceLocation loc = info->record()->getInnerLocStart();
981 SourceManager& manager = instance_.getSourceManager();
982 FullSourceLoc full_loc(loc, manager);
983 diagnostic_.Report(full_loc, diag_class_requires_trace_method_)
984 << info->record();
985
986 for (RecordInfo::Bases::iterator it = info->GetBases().begin();
987 it != info->GetBases().end();
988 ++it) {
989 if (it->second.NeedsTracing().IsNeeded())
990 NoteBaseRequiresTracing(&it->second);
991 }
992
993 for (RecordInfo::Fields::iterator it = info->GetFields().begin();
994 it != info->GetFields().end();
995 ++it) {
996 if (!it->second.IsProperlyTraced())
997 NoteFieldRequiresTracing(info, it->first);
998 }
999 }
1000
1001 void BlinkGCPluginConsumer::ReportBaseRequiresTracing(
1002 RecordInfo* derived,
1003 CXXMethodDecl* trace,
1004 CXXRecordDecl* base) {
1005 SourceLocation loc = trace->getLocStart();
1006 SourceManager& manager = instance_.getSourceManager();
1007 FullSourceLoc full_loc(loc, manager);
1008 diagnostic_.Report(full_loc, diag_base_requires_tracing_)
1009 << base << derived->record();
1010 }
1011
1012 void BlinkGCPluginConsumer::ReportFieldsRequireTracing(
1013 RecordInfo* info,
1014 CXXMethodDecl* trace) {
1015 SourceLocation loc = trace->getLocStart();
1016 SourceManager& manager = instance_.getSourceManager();
1017 FullSourceLoc full_loc(loc, manager);
1018 diagnostic_.Report(full_loc, diag_fields_require_tracing_)
1019 << info->record();
1020 for (RecordInfo::Fields::iterator it = info->GetFields().begin();
1021 it != info->GetFields().end();
1022 ++it) {
1023 if (!it->second.IsProperlyTraced())
1024 NoteFieldRequiresTracing(info, it->first);
1025 }
1026 }
1027
1028 void BlinkGCPluginConsumer::ReportClassContainsInvalidFields(
1029 RecordInfo* info,
1030 CheckFieldsVisitor::Errors* errors) {
1031 SourceLocation loc = info->record()->getLocStart();
1032 SourceManager& manager = instance_.getSourceManager();
1033 FullSourceLoc full_loc(loc, manager);
1034 bool only_warnings = options_.warn_raw_ptr;
1035 for (CheckFieldsVisitor::Errors::iterator it = errors->begin();
1036 only_warnings && it != errors->end();
1037 ++it) {
1038 if (!CheckFieldsVisitor::IsWarning(it->second))
1039 only_warnings = false;
1040 }
1041 diagnostic_.Report(full_loc,
1042 only_warnings ?
1043 diag_class_contains_invalid_fields_warning_ :
1044 diag_class_contains_invalid_fields_)
1045 << info->record();
1046 for (CheckFieldsVisitor::Errors::iterator it = errors->begin();
1047 it != errors->end();
1048 ++it) {
1049 unsigned error;
1050 if (CheckFieldsVisitor::IsRawPtrError(it->second)) {
1051 error = diag_raw_ptr_to_gc_managed_class_note_;
1052 } else if (CheckFieldsVisitor::IsReferencePtrError(it->second)) {
1053 error = diag_reference_ptr_to_gc_managed_class_note_;
1054 } else if (it->second == CheckFieldsVisitor::kRefPtrToGCManaged) {
1055 error = diag_ref_ptr_to_gc_managed_class_note_;
1056 } else if (it->second == CheckFieldsVisitor::kOwnPtrToGCManaged) {
1057 error = diag_own_ptr_to_gc_managed_class_note_;
1058 } else if (it->second == CheckFieldsVisitor::kMemberToGCUnmanaged) {
1059 error = diag_member_to_gc_unmanaged_class_note_;
1060 } else if (it->second == CheckFieldsVisitor::kMemberInUnmanaged) {
1061 error = diag_member_in_unmanaged_class_note_;
1062 } else if (it->second == CheckFieldsVisitor::kPtrFromHeapToStack) {
1063 error = diag_stack_allocated_field_note_;
1064 } else if (it->second == CheckFieldsVisitor::kGCDerivedPartObject) {
1065 error = diag_part_object_to_gc_derived_class_note_;
1066 } else {
1067 assert(false && "Unknown field error");
1068 }
1069 NoteField(it->first, error);
1070 }
1071 }
1072
1073 void BlinkGCPluginConsumer::ReportClassContainsGCRoots(
1074 RecordInfo* info,
1075 CheckGCRootsVisitor::Errors* errors) {
1076 SourceLocation loc = info->record()->getLocStart();
1077 SourceManager& manager = instance_.getSourceManager();
1078 FullSourceLoc full_loc(loc, manager);
1079 for (CheckGCRootsVisitor::Errors::iterator it = errors->begin();
1080 it != errors->end();
1081 ++it) {
1082 CheckGCRootsVisitor::RootPath::iterator path = it->begin();
1083 FieldPoint* point = *path;
1084 diagnostic_.Report(full_loc, diag_class_contains_gc_root_)
1085 << info->record() << point->field();
1086 while (++path != it->end()) {
1087 NotePartObjectContainsGCRoot(point);
1088 point = *path;
1089 }
1090 NoteFieldContainsGCRoot(point);
1091 }
1092 }
1093
1094 void BlinkGCPluginConsumer::ReportFinalizerAccessesFinalizedFields(
1095 CXXMethodDecl* dtor,
1096 CheckFinalizerVisitor::Errors* fields) {
1097 for (CheckFinalizerVisitor::Errors::iterator it = fields->begin();
1098 it != fields->end();
1099 ++it) {
1100 SourceLocation loc = it->member->getLocStart();
1101 SourceManager& manager = instance_.getSourceManager();
1102 bool as_eagerly_finalized = it->as_eagerly_finalized;
1103 unsigned diag_error = as_eagerly_finalized ?
1104 diag_finalizer_eagerly_finalized_field_ :
1105 diag_finalizer_accesses_finalized_field_;
1106 unsigned diag_note = as_eagerly_finalized ?
1107 diag_eagerly_finalized_field_note_ :
1108 diag_finalized_field_note_;
1109 FullSourceLoc full_loc(loc, manager);
1110 diagnostic_.Report(full_loc, diag_error)
1111 << dtor << it->field->field();
1112 NoteField(it->field, diag_note);
1113 }
1114 }
1115
1116 void BlinkGCPluginConsumer::ReportClassRequiresFinalization(RecordInfo* info) {
1117 SourceLocation loc = info->record()->getInnerLocStart();
1118 SourceManager& manager = instance_.getSourceManager();
1119 FullSourceLoc full_loc(loc, manager);
1120 diagnostic_.Report(full_loc, diag_class_requires_finalization_)
1121 << info->record();
1122 }
1123
1124 void BlinkGCPluginConsumer::ReportClassDoesNotRequireFinalization(
1125 RecordInfo* info) {
1126 SourceLocation loc = info->record()->getInnerLocStart();
1127 SourceManager& manager = instance_.getSourceManager();
1128 FullSourceLoc full_loc(loc, manager);
1129 diagnostic_.Report(full_loc, diag_class_does_not_require_finalization_)
1130 << info->record();
1131 }
1132
1133 void BlinkGCPluginConsumer::ReportClassMustDeclareGCMixinTraceMethod(
1134 RecordInfo* info) {
1135 SourceLocation loc = info->record()->getInnerLocStart();
1136 SourceManager& manager = instance_.getSourceManager();
1137 FullSourceLoc full_loc(loc, manager);
1138 diagnostic_.Report(full_loc, diag_class_must_declare_gc_mixin_trace_method_)
1139 << info->record();
1140 }
1141
1142 void BlinkGCPluginConsumer::ReportOverriddenNonVirtualTrace(
1143 RecordInfo* info,
1144 CXXMethodDecl* trace,
1145 CXXMethodDecl* overridden) {
1146 SourceLocation loc = trace->getLocStart();
1147 SourceManager& manager = instance_.getSourceManager();
1148 FullSourceLoc full_loc(loc, manager);
1149 diagnostic_.Report(full_loc, diag_overridden_non_virtual_trace_)
1150 << info->record() << overridden->getParent();
1151 NoteOverriddenNonVirtualTrace(overridden);
1152 }
1153
1154 void BlinkGCPluginConsumer::ReportMissingTraceDispatchMethod(RecordInfo* info) {
1155 ReportMissingDispatchMethod(info, diag_missing_trace_dispatch_method_);
1156 }
1157
1158 void BlinkGCPluginConsumer::ReportMissingFinalizeDispatchMethod(
1159 RecordInfo* info) {
1160 ReportMissingDispatchMethod(info, diag_missing_finalize_dispatch_method_);
1161 }
1162
1163 void BlinkGCPluginConsumer::ReportMissingDispatchMethod(
1164 RecordInfo* info,
1165 unsigned error) {
1166 SourceLocation loc = info->record()->getInnerLocStart();
1167 SourceManager& manager = instance_.getSourceManager();
1168 FullSourceLoc full_loc(loc, manager);
1169 diagnostic_.Report(full_loc, error) << info->record();
1170 }
1171
1172 void BlinkGCPluginConsumer::ReportVirtualAndManualDispatch(
1173 RecordInfo* info,
1174 CXXMethodDecl* dispatch) {
1175 SourceLocation loc = info->record()->getInnerLocStart();
1176 SourceManager& manager = instance_.getSourceManager();
1177 FullSourceLoc full_loc(loc, manager);
1178 diagnostic_.Report(full_loc, diag_virtual_and_manual_dispatch_)
1179 << info->record();
1180 NoteManualDispatchMethod(dispatch);
1181 }
1182
1183 void BlinkGCPluginConsumer::ReportMissingTraceDispatch(
1184 const FunctionDecl* dispatch,
1185 RecordInfo* receiver) {
1186 ReportMissingDispatch(dispatch, receiver, diag_missing_trace_dispatch_);
1187 }
1188
1189 void BlinkGCPluginConsumer::ReportMissingFinalizeDispatch(
1190 const FunctionDecl* dispatch,
1191 RecordInfo* receiver) {
1192 ReportMissingDispatch(dispatch, receiver, diag_missing_finalize_dispatch_);
1193 }
1194
1195 void BlinkGCPluginConsumer::ReportMissingDispatch(
1196 const FunctionDecl* dispatch,
1197 RecordInfo* receiver,
1198 unsigned error) {
1199 SourceLocation loc = dispatch->getLocStart();
1200 SourceManager& manager = instance_.getSourceManager();
1201 FullSourceLoc full_loc(loc, manager);
1202 diagnostic_.Report(full_loc, error) << receiver->record();
1203 }
1204
1205 void BlinkGCPluginConsumer::ReportDerivesNonStackAllocated(
1206 RecordInfo* info,
1207 BasePoint* base) {
1208 SourceLocation loc = base->spec().getLocStart();
1209 SourceManager& manager = instance_.getSourceManager();
1210 FullSourceLoc full_loc(loc, manager);
1211 diagnostic_.Report(full_loc, diag_derives_non_stack_allocated_)
1212 << info->record() << base->info()->record();
1213 }
1214
1215 void BlinkGCPluginConsumer::ReportClassOverridesNew(
1216 RecordInfo* info,
1217 CXXMethodDecl* newop) {
1218 SourceLocation loc = newop->getLocStart();
1219 SourceManager& manager = instance_.getSourceManager();
1220 FullSourceLoc full_loc(loc, manager);
1221 diagnostic_.Report(full_loc, diag_class_overrides_new_) << info->record();
1222 }
1223
1224 void BlinkGCPluginConsumer::ReportClassDeclaresPureVirtualTrace(
1225 RecordInfo* info,
1226 CXXMethodDecl* trace) {
1227 SourceLocation loc = trace->getLocStart();
1228 SourceManager& manager = instance_.getSourceManager();
1229 FullSourceLoc full_loc(loc, manager);
1230 diagnostic_.Report(full_loc, diag_class_declares_pure_virtual_trace_)
1231 << info->record();
1232 }
1233
1234 void BlinkGCPluginConsumer::ReportLeftMostBaseMustBePolymorphic(
1235 RecordInfo* derived,
1236 CXXRecordDecl* base) {
1237 SourceLocation loc = base->getLocStart();
1238 SourceManager& manager = instance_.getSourceManager();
1239 FullSourceLoc full_loc(loc, manager);
1240 diagnostic_.Report(full_loc, diag_left_most_base_must_be_polymorphic_)
1241 << base << derived->record();
1242 }
1243
1244 void BlinkGCPluginConsumer::ReportBaseClassMustDeclareVirtualTrace(
1245 RecordInfo* derived,
1246 CXXRecordDecl* base) {
1247 SourceLocation loc = base->getLocStart();
1248 SourceManager& manager = instance_.getSourceManager();
1249 FullSourceLoc full_loc(loc, manager);
1250 diagnostic_.Report(full_loc, diag_base_class_must_declare_virtual_trace_)
1251 << base << derived->record();
1252 }
1253
1254 void BlinkGCPluginConsumer::NoteManualDispatchMethod(CXXMethodDecl* dispatch) {
1255 SourceLocation loc = dispatch->getLocStart();
1256 SourceManager& manager = instance_.getSourceManager();
1257 FullSourceLoc full_loc(loc, manager);
1258 diagnostic_.Report(full_loc, diag_manual_dispatch_method_note_) << dispatch;
1259 }
1260
1261 void BlinkGCPluginConsumer::NoteBaseRequiresTracing(BasePoint* base) {
1262 SourceLocation loc = base->spec().getLocStart();
1263 SourceManager& manager = instance_.getSourceManager();
1264 FullSourceLoc full_loc(loc, manager);
1265 diagnostic_.Report(full_loc, diag_base_requires_tracing_note_)
1266 << base->info()->record();
1267 }
1268
1269 void BlinkGCPluginConsumer::NoteFieldRequiresTracing(
1270 RecordInfo* holder,
1271 FieldDecl* field) {
1272 NoteField(field, diag_field_requires_tracing_note_);
1273 }
1274
1275 void BlinkGCPluginConsumer::NotePartObjectContainsGCRoot(FieldPoint* point) {
1276 FieldDecl* field = point->field();
1277 SourceLocation loc = field->getLocStart();
1278 SourceManager& manager = instance_.getSourceManager();
1279 FullSourceLoc full_loc(loc, manager);
1280 diagnostic_.Report(full_loc, diag_part_object_contains_gc_root_note_)
1281 << field << field->getParent();
1282 }
1283
1284 void BlinkGCPluginConsumer::NoteFieldContainsGCRoot(FieldPoint* point) {
1285 NoteField(point, diag_field_contains_gc_root_note_);
1286 }
1287
1288 void BlinkGCPluginConsumer::NoteUserDeclaredDestructor(CXXMethodDecl* dtor) {
1289 SourceLocation loc = dtor->getLocStart();
1290 SourceManager& manager = instance_.getSourceManager();
1291 FullSourceLoc full_loc(loc, manager);
1292 diagnostic_.Report(full_loc, diag_user_declared_destructor_note_);
1293 }
1294
1295 void BlinkGCPluginConsumer::NoteUserDeclaredFinalizer(CXXMethodDecl* dtor) {
1296 SourceLocation loc = dtor->getLocStart();
1297 SourceManager& manager = instance_.getSourceManager();
1298 FullSourceLoc full_loc(loc, manager);
1299 diagnostic_.Report(full_loc, diag_user_declared_finalizer_note_);
1300 }
1301
1302 void BlinkGCPluginConsumer::NoteBaseRequiresFinalization(BasePoint* base) {
1303 SourceLocation loc = base->spec().getLocStart();
1304 SourceManager& manager = instance_.getSourceManager();
1305 FullSourceLoc full_loc(loc, manager);
1306 diagnostic_.Report(full_loc, diag_base_requires_finalization_note_)
1307 << base->info()->record();
1308 }
1309
1310 void BlinkGCPluginConsumer::NoteField(FieldPoint* point, unsigned note) {
1311 NoteField(point->field(), note);
1312 }
1313
1314 void BlinkGCPluginConsumer::NoteField(FieldDecl* field, unsigned note) {
1315 SourceLocation loc = field->getLocStart();
1316 SourceManager& manager = instance_.getSourceManager();
1317 FullSourceLoc full_loc(loc, manager);
1318 diagnostic_.Report(full_loc, note) << field;
1319 }
1320
1321 void BlinkGCPluginConsumer::NoteOverriddenNonVirtualTrace(
1322 CXXMethodDecl* overridden) {
1323 SourceLocation loc = overridden->getLocStart();
1324 SourceManager& manager = instance_.getSourceManager();
1325 FullSourceLoc full_loc(loc, manager);
1326 diagnostic_.Report(full_loc, diag_overridden_non_virtual_trace_note_)
1327 << overridden;
1328 }
OLDNEW
« no previous file with comments | « tools/clang/blink_gc_plugin/BlinkGCPluginConsumer.h ('k') | tools/clang/blink_gc_plugin/BlinkGCPluginOptions.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698