Home | History | Annotate | Download | only in blink_gc_plugin
      1 // Copyright 2016 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 "DiagnosticsReporter.h"
      6 
      7 using namespace clang;
      8 
      9 namespace {
     10 
     11 const char kClassMustLeftMostlyDeriveGC[] =
     12     "[blink-gc] Class %0 must derive its GC base in the left-most position.";
     13 
     14 const char kClassRequiresTraceMethod[] =
     15     "[blink-gc] Class %0 requires a trace method.";
     16 
     17 const char kBaseRequiresTracing[] =
     18     "[blink-gc] Base class %0 of derived class %1 requires tracing.";
     19 
     20 const char kBaseRequiresTracingNote[] =
     21     "[blink-gc] Untraced base class %0 declared here:";
     22 
     23 const char kFieldsRequireTracing[] =
     24     "[blink-gc] Class %0 has untraced fields that require tracing.";
     25 
     26 const char kFieldsImproperlyTraced[] =
     27     "[blink-gc] Class %0 has untraced or not traceable fields.";
     28 
     29 const char kFieldRequiresTracingNote[] =
     30     "[blink-gc] Untraced field %0 declared here:";
     31 
     32 const char kFieldShouldNotBeTracedNote[] =
     33     "[blink-gc] Untraceable field %0 declared here:";
     34 
     35 const char kClassContainsInvalidFields[] =
     36     "[blink-gc] Class %0 contains invalid fields.";
     37 
     38 const char kClassContainsGCRoot[] =
     39     "[blink-gc] Class %0 contains GC root in field %1.";
     40 
     41 const char kClassRequiresFinalization[] =
     42     "[blink-gc] Class %0 requires finalization.";
     43 
     44 const char kClassDoesNotRequireFinalization[] =
     45     "[blink-gc] Class %0 may not require finalization.";
     46 
     47 const char kFinalizerAccessesFinalizedField[] =
     48     "[blink-gc] Finalizer %0 accesses potentially finalized field %1.";
     49 
     50 const char kFinalizerAccessesEagerlyFinalizedField[] =
     51     "[blink-gc] Finalizer %0 accesses eagerly finalized field %1.";
     52 
     53 const char kRawPtrToGCManagedClassNote[] =
     54     "[blink-gc] Raw pointer field %0 to a GC managed class declared here:";
     55 
     56 const char kRefPtrToGCManagedClassNote[] =
     57     "[blink-gc] RefPtr field %0 to a GC managed class declared here:";
     58 
     59 const char kReferencePtrToGCManagedClassNote[] =
     60     "[blink-gc] Reference pointer field %0 to a GC managed class"
     61     " declared here:";
     62 
     63 const char kOwnPtrToGCManagedClassNote[] =
     64     "[blink-gc] OwnPtr field %0 to a GC managed class declared here:";
     65 
     66 const char kUniquePtrToGCManagedClassNote[] =
     67     "[blink-gc] std::unique_ptr field %0 to a GC managed class declared here:";
     68 
     69 const char kMemberToGCUnmanagedClassNote[] =
     70     "[blink-gc] Member field %0 to non-GC managed class declared here:";
     71 
     72 const char kStackAllocatedFieldNote[] =
     73     "[blink-gc] Stack-allocated field %0 declared here:";
     74 
     75 const char kMemberInUnmanagedClassNote[] =
     76     "[blink-gc] Member field %0 in unmanaged class declared here:";
     77 
     78 const char kPartObjectToGCDerivedClassNote[] =
     79     "[blink-gc] Part-object field %0 to a GC derived class declared here:";
     80 
     81 const char kPartObjectContainsGCRootNote[] =
     82     "[blink-gc] Field %0 with embedded GC root in %1 declared here:";
     83 
     84 const char kFieldContainsGCRootNote[] =
     85     "[blink-gc] Field %0 defining a GC root declared here:";
     86 
     87 const char kOverriddenNonVirtualTrace[] =
     88     "[blink-gc] Class %0 overrides non-virtual trace of base class %1.";
     89 
     90 const char kOverriddenNonVirtualTraceNote[] =
     91     "[blink-gc] Non-virtual trace method declared here:";
     92 
     93 const char kMissingTraceDispatchMethod[] =
     94     "[blink-gc] Class %0 is missing manual trace dispatch.";
     95 
     96 const char kMissingFinalizeDispatchMethod[] =
     97     "[blink-gc] Class %0 is missing manual finalize dispatch.";
     98 
     99 const char kVirtualAndManualDispatch[] =
    100     "[blink-gc] Class %0 contains or inherits virtual methods"
    101     " but implements manual dispatching.";
    102 
    103 const char kMissingTraceDispatch[] =
    104     "[blink-gc] Missing dispatch to class %0 in manual trace dispatch.";
    105 
    106 const char kMissingFinalizeDispatch[] =
    107     "[blink-gc] Missing dispatch to class %0 in manual finalize dispatch.";
    108 
    109 const char kFinalizedFieldNote[] =
    110     "[blink-gc] Potentially finalized field %0 declared here:";
    111 
    112 const char kEagerlyFinalizedFieldNote[] =
    113     "[blink-gc] Field %0 having eagerly finalized value, declared here:";
    114 
    115 const char kUserDeclaredDestructorNote[] =
    116     "[blink-gc] User-declared destructor declared here:";
    117 
    118 const char kUserDeclaredFinalizerNote[] =
    119     "[blink-gc] User-declared finalizer declared here:";
    120 
    121 const char kBaseRequiresFinalizationNote[] =
    122     "[blink-gc] Base class %0 requiring finalization declared here:";
    123 
    124 const char kFieldRequiresFinalizationNote[] =
    125     "[blink-gc] Field %0 requiring finalization declared here:";
    126 
    127 const char kManualDispatchMethodNote[] =
    128     "[blink-gc] Manual dispatch %0 declared here:";
    129 
    130 const char kStackAllocatedDerivesGarbageCollected[] =
    131     "[blink-gc] Stack-allocated class %0 derives class %1"
    132     " which is garbage collected.";
    133 
    134 const char kClassOverridesNew[] =
    135     "[blink-gc] Garbage collected class %0"
    136     " is not permitted to override its new operator.";
    137 
    138 const char kClassDeclaresPureVirtualTrace[] =
    139     "[blink-gc] Garbage collected class %0"
    140     " is not permitted to declare a pure-virtual trace method.";
    141 
    142 const char kLeftMostBaseMustBePolymorphic[] =
    143     "[blink-gc] Left-most base class %0 of derived class %1"
    144     " must be polymorphic.";
    145 
    146 const char kBaseClassMustDeclareVirtualTrace[] =
    147     "[blink-gc] Left-most base class %0 of derived class %1"
    148     " must define a virtual trace method.";
    149 
    150 } // namespace
    151 
    152 DiagnosticBuilder DiagnosticsReporter::ReportDiagnostic(
    153     SourceLocation location,
    154     unsigned diag_id) {
    155   SourceManager& manager = instance_.getSourceManager();
    156   FullSourceLoc full_loc(location, manager);
    157   return diagnostic_.Report(full_loc, diag_id);
    158 }
    159 
    160 DiagnosticsReporter::DiagnosticsReporter(
    161     clang::CompilerInstance& instance)
    162     : instance_(instance),
    163       diagnostic_(instance.getDiagnostics())
    164 {
    165   // Register warning/error messages.
    166   diag_class_must_left_mostly_derive_gc_ = diagnostic_.getCustomDiagID(
    167       getErrorLevel(), kClassMustLeftMostlyDeriveGC);
    168   diag_class_requires_trace_method_ =
    169       diagnostic_.getCustomDiagID(getErrorLevel(), kClassRequiresTraceMethod);
    170   diag_base_requires_tracing_ =
    171       diagnostic_.getCustomDiagID(getErrorLevel(), kBaseRequiresTracing);
    172   diag_fields_require_tracing_ =
    173       diagnostic_.getCustomDiagID(getErrorLevel(), kFieldsRequireTracing);
    174   diag_fields_improperly_traced_ =
    175       diagnostic_.getCustomDiagID(getErrorLevel(), kFieldsImproperlyTraced);
    176   diag_class_contains_invalid_fields_ = diagnostic_.getCustomDiagID(
    177       getErrorLevel(), kClassContainsInvalidFields);
    178   diag_class_contains_gc_root_ =
    179       diagnostic_.getCustomDiagID(getErrorLevel(), kClassContainsGCRoot);
    180   diag_class_requires_finalization_ = diagnostic_.getCustomDiagID(
    181       getErrorLevel(), kClassRequiresFinalization);
    182   diag_class_does_not_require_finalization_ = diagnostic_.getCustomDiagID(
    183       DiagnosticsEngine::Warning, kClassDoesNotRequireFinalization);
    184   diag_finalizer_accesses_finalized_field_ = diagnostic_.getCustomDiagID(
    185       getErrorLevel(), kFinalizerAccessesFinalizedField);
    186   diag_finalizer_eagerly_finalized_field_ = diagnostic_.getCustomDiagID(
    187       getErrorLevel(), kFinalizerAccessesEagerlyFinalizedField);
    188   diag_overridden_non_virtual_trace_ = diagnostic_.getCustomDiagID(
    189       getErrorLevel(), kOverriddenNonVirtualTrace);
    190   diag_missing_trace_dispatch_method_ = diagnostic_.getCustomDiagID(
    191       getErrorLevel(), kMissingTraceDispatchMethod);
    192   diag_missing_finalize_dispatch_method_ = diagnostic_.getCustomDiagID(
    193       getErrorLevel(), kMissingFinalizeDispatchMethod);
    194   diag_virtual_and_manual_dispatch_ =
    195       diagnostic_.getCustomDiagID(getErrorLevel(), kVirtualAndManualDispatch);
    196   diag_missing_trace_dispatch_ =
    197       diagnostic_.getCustomDiagID(getErrorLevel(), kMissingTraceDispatch);
    198   diag_missing_finalize_dispatch_ =
    199       diagnostic_.getCustomDiagID(getErrorLevel(), kMissingFinalizeDispatch);
    200   diag_stack_allocated_derives_gc_ = diagnostic_.getCustomDiagID(
    201       getErrorLevel(), kStackAllocatedDerivesGarbageCollected);
    202   diag_class_overrides_new_ =
    203       diagnostic_.getCustomDiagID(getErrorLevel(), kClassOverridesNew);
    204   diag_class_declares_pure_virtual_trace_ = diagnostic_.getCustomDiagID(
    205       getErrorLevel(), kClassDeclaresPureVirtualTrace);
    206   diag_left_most_base_must_be_polymorphic_ = diagnostic_.getCustomDiagID(
    207       getErrorLevel(), kLeftMostBaseMustBePolymorphic);
    208   diag_base_class_must_declare_virtual_trace_ = diagnostic_.getCustomDiagID(
    209       getErrorLevel(), kBaseClassMustDeclareVirtualTrace);
    210 
    211   // Register note messages.
    212   diag_base_requires_tracing_note_ = diagnostic_.getCustomDiagID(
    213       DiagnosticsEngine::Note, kBaseRequiresTracingNote);
    214   diag_field_requires_tracing_note_ = diagnostic_.getCustomDiagID(
    215       DiagnosticsEngine::Note, kFieldRequiresTracingNote);
    216   diag_field_should_not_be_traced_note_ = diagnostic_.getCustomDiagID(
    217       DiagnosticsEngine::Note, kFieldShouldNotBeTracedNote);
    218   diag_raw_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
    219       DiagnosticsEngine::Note, kRawPtrToGCManagedClassNote);
    220   diag_ref_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
    221       DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote);
    222   diag_reference_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
    223       DiagnosticsEngine::Note, kReferencePtrToGCManagedClassNote);
    224   diag_own_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
    225       DiagnosticsEngine::Note, kOwnPtrToGCManagedClassNote);
    226   diag_unique_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
    227       DiagnosticsEngine::Note, kUniquePtrToGCManagedClassNote);
    228   diag_member_to_gc_unmanaged_class_note_ = diagnostic_.getCustomDiagID(
    229       DiagnosticsEngine::Note, kMemberToGCUnmanagedClassNote);
    230   diag_stack_allocated_field_note_ = diagnostic_.getCustomDiagID(
    231       DiagnosticsEngine::Note, kStackAllocatedFieldNote);
    232   diag_member_in_unmanaged_class_note_ = diagnostic_.getCustomDiagID(
    233       DiagnosticsEngine::Note, kMemberInUnmanagedClassNote);
    234   diag_part_object_to_gc_derived_class_note_ = diagnostic_.getCustomDiagID(
    235       DiagnosticsEngine::Note, kPartObjectToGCDerivedClassNote);
    236   diag_part_object_contains_gc_root_note_ = diagnostic_.getCustomDiagID(
    237       DiagnosticsEngine::Note, kPartObjectContainsGCRootNote);
    238   diag_field_contains_gc_root_note_ = diagnostic_.getCustomDiagID(
    239       DiagnosticsEngine::Note, kFieldContainsGCRootNote);
    240   diag_finalized_field_note_ = diagnostic_.getCustomDiagID(
    241       DiagnosticsEngine::Note, kFinalizedFieldNote);
    242   diag_eagerly_finalized_field_note_ = diagnostic_.getCustomDiagID(
    243       DiagnosticsEngine::Note, kEagerlyFinalizedFieldNote);
    244   diag_user_declared_destructor_note_ = diagnostic_.getCustomDiagID(
    245       DiagnosticsEngine::Note, kUserDeclaredDestructorNote);
    246   diag_user_declared_finalizer_note_ = diagnostic_.getCustomDiagID(
    247       DiagnosticsEngine::Note, kUserDeclaredFinalizerNote);
    248   diag_base_requires_finalization_note_ = diagnostic_.getCustomDiagID(
    249       DiagnosticsEngine::Note, kBaseRequiresFinalizationNote);
    250   diag_field_requires_finalization_note_ = diagnostic_.getCustomDiagID(
    251       DiagnosticsEngine::Note, kFieldRequiresFinalizationNote);
    252   diag_overridden_non_virtual_trace_note_ = diagnostic_.getCustomDiagID(
    253       DiagnosticsEngine::Note, kOverriddenNonVirtualTraceNote);
    254   diag_manual_dispatch_method_note_ = diagnostic_.getCustomDiagID(
    255       DiagnosticsEngine::Note, kManualDispatchMethodNote);
    256 }
    257 
    258 bool DiagnosticsReporter::hasErrorOccurred() const
    259 {
    260   return diagnostic_.hasErrorOccurred();
    261 }
    262 
    263 DiagnosticsEngine::Level DiagnosticsReporter::getErrorLevel() const {
    264   return diagnostic_.getWarningsAsErrors() ? DiagnosticsEngine::Error
    265                                            : DiagnosticsEngine::Warning;
    266 }
    267 
    268 void DiagnosticsReporter::ClassMustLeftMostlyDeriveGC(
    269     RecordInfo* info) {
    270   ReportDiagnostic(info->record()->getInnerLocStart(),
    271                    diag_class_must_left_mostly_derive_gc_)
    272       << info->record();
    273 }
    274 
    275 void DiagnosticsReporter::ClassRequiresTraceMethod(RecordInfo* info) {
    276   ReportDiagnostic(info->record()->getInnerLocStart(),
    277                    diag_class_requires_trace_method_)
    278       << info->record();
    279 
    280   for (auto& base : info->GetBases())
    281     if (base.second.NeedsTracing().IsNeeded())
    282       NoteBaseRequiresTracing(&base.second);
    283 
    284   for (auto& field : info->GetFields())
    285     if (!field.second.IsProperlyTraced())
    286       NoteFieldRequiresTracing(info, field.first);
    287 }
    288 
    289 void DiagnosticsReporter::BaseRequiresTracing(
    290     RecordInfo* derived,
    291     CXXMethodDecl* trace,
    292     CXXRecordDecl* base) {
    293   ReportDiagnostic(trace->getLocStart(), diag_base_requires_tracing_)
    294       << base << derived->record();
    295 }
    296 
    297 void DiagnosticsReporter::FieldsImproperlyTraced(
    298     RecordInfo* info,
    299     CXXMethodDecl* trace) {
    300   // Only mention untraceable in header diagnostic if they appear.
    301   unsigned diag = diag_fields_require_tracing_;
    302   for (auto& field : info->GetFields()) {
    303     if (field.second.IsInproperlyTraced()) {
    304       diag = diag_fields_improperly_traced_;
    305       break;
    306     }
    307   }
    308   ReportDiagnostic(trace->getLocStart(), diag)
    309       << info->record();
    310   for (auto& field : info->GetFields()) {
    311     if (!field.second.IsProperlyTraced())
    312       NoteFieldRequiresTracing(info, field.first);
    313     if (field.second.IsInproperlyTraced())
    314       NoteFieldShouldNotBeTraced(info, field.first);
    315   }
    316 }
    317 
    318 void DiagnosticsReporter::ClassContainsInvalidFields(
    319     RecordInfo* info,
    320     const CheckFieldsVisitor::Errors& errors) {
    321 
    322   ReportDiagnostic(info->record()->getLocStart(),
    323                    diag_class_contains_invalid_fields_)
    324       << info->record();
    325 
    326   for (auto& error : errors) {
    327     unsigned note;
    328     if (error.second == CheckFieldsVisitor::kRawPtrToGCManaged) {
    329       note = diag_raw_ptr_to_gc_managed_class_note_;
    330     } else if (error.second == CheckFieldsVisitor::kRefPtrToGCManaged) {
    331       note = diag_ref_ptr_to_gc_managed_class_note_;
    332     } else if (error.second == CheckFieldsVisitor::kReferencePtrToGCManaged) {
    333       note = diag_reference_ptr_to_gc_managed_class_note_;
    334     } else if (error.second == CheckFieldsVisitor::kOwnPtrToGCManaged) {
    335       note = diag_own_ptr_to_gc_managed_class_note_;
    336     } else if (error.second == CheckFieldsVisitor::kUniquePtrToGCManaged) {
    337       note = diag_unique_ptr_to_gc_managed_class_note_;
    338     } else if (error.second == CheckFieldsVisitor::kMemberToGCUnmanaged) {
    339       note = diag_member_to_gc_unmanaged_class_note_;
    340     } else if (error.second == CheckFieldsVisitor::kMemberInUnmanaged) {
    341       note = diag_member_in_unmanaged_class_note_;
    342     } else if (error.second == CheckFieldsVisitor::kPtrFromHeapToStack) {
    343       note = diag_stack_allocated_field_note_;
    344     } else if (error.second == CheckFieldsVisitor::kGCDerivedPartObject) {
    345       note = diag_part_object_to_gc_derived_class_note_;
    346     } else {
    347       assert(false && "Unknown field error");
    348     }
    349     NoteField(error.first, note);
    350   }
    351 }
    352 
    353 void DiagnosticsReporter::ClassContainsGCRoots(
    354     RecordInfo* info,
    355     const CheckGCRootsVisitor::Errors& errors) {
    356   for (auto& error : errors) {
    357     FieldPoint* point = nullptr;
    358     for (FieldPoint* path : error) {
    359       if (!point) {
    360         point = path;
    361         ReportDiagnostic(info->record()->getLocStart(),
    362                          diag_class_contains_gc_root_)
    363             << info->record() << point->field();
    364         continue;
    365       }
    366       NotePartObjectContainsGCRoot(point);
    367       point = path;
    368     }
    369     NoteFieldContainsGCRoot(point);
    370   }
    371 }
    372 
    373 void DiagnosticsReporter::FinalizerAccessesFinalizedFields(
    374     CXXMethodDecl* dtor,
    375     const CheckFinalizerVisitor::Errors& errors) {
    376   for (auto& error : errors) {
    377     bool as_eagerly_finalized = error.as_eagerly_finalized;
    378     unsigned diag_error = as_eagerly_finalized ?
    379                           diag_finalizer_eagerly_finalized_field_ :
    380                           diag_finalizer_accesses_finalized_field_;
    381     unsigned diag_note = as_eagerly_finalized ?
    382                          diag_eagerly_finalized_field_note_ :
    383                          diag_finalized_field_note_;
    384     ReportDiagnostic(error.member->getLocStart(), diag_error)
    385         << dtor << error.field->field();
    386     NoteField(error.field, diag_note);
    387   }
    388 }
    389 
    390 void DiagnosticsReporter::ClassRequiresFinalization(RecordInfo* info) {
    391   ReportDiagnostic(info->record()->getInnerLocStart(),
    392                    diag_class_requires_finalization_)
    393       << info->record();
    394 }
    395 
    396 void DiagnosticsReporter::ClassDoesNotRequireFinalization(
    397     RecordInfo* info) {
    398   ReportDiagnostic(info->record()->getInnerLocStart(),
    399                    diag_class_does_not_require_finalization_)
    400       << info->record();
    401 }
    402 
    403 void DiagnosticsReporter::OverriddenNonVirtualTrace(
    404     RecordInfo* info,
    405     CXXMethodDecl* trace,
    406     CXXMethodDecl* overridden) {
    407   ReportDiagnostic(trace->getLocStart(), diag_overridden_non_virtual_trace_)
    408       << info->record() << overridden->getParent();
    409   NoteOverriddenNonVirtualTrace(overridden);
    410 }
    411 
    412 void DiagnosticsReporter::MissingTraceDispatchMethod(RecordInfo* info) {
    413   ReportMissingDispatchMethod(info, diag_missing_trace_dispatch_method_);
    414 }
    415 
    416 void DiagnosticsReporter::MissingFinalizeDispatchMethod(
    417     RecordInfo* info) {
    418   ReportMissingDispatchMethod(info, diag_missing_finalize_dispatch_method_);
    419 }
    420 
    421 void DiagnosticsReporter::ReportMissingDispatchMethod(
    422     RecordInfo* info,
    423     unsigned error) {
    424   ReportDiagnostic(info->record()->getInnerLocStart(), error)
    425       << info->record();
    426 }
    427 
    428 void DiagnosticsReporter::VirtualAndManualDispatch(
    429     RecordInfo* info,
    430     CXXMethodDecl* dispatch) {
    431   ReportDiagnostic(info->record()->getInnerLocStart(),
    432                    diag_virtual_and_manual_dispatch_)
    433       << info->record();
    434   NoteManualDispatchMethod(dispatch);
    435 }
    436 
    437 void DiagnosticsReporter::MissingTraceDispatch(
    438     const FunctionDecl* dispatch,
    439     RecordInfo* receiver) {
    440   ReportMissingDispatch(dispatch, receiver, diag_missing_trace_dispatch_);
    441 }
    442 
    443 void DiagnosticsReporter::MissingFinalizeDispatch(
    444     const FunctionDecl* dispatch,
    445     RecordInfo* receiver) {
    446   ReportMissingDispatch(dispatch, receiver, diag_missing_finalize_dispatch_);
    447 }
    448 
    449 void DiagnosticsReporter::ReportMissingDispatch(
    450     const FunctionDecl* dispatch,
    451     RecordInfo* receiver,
    452     unsigned error) {
    453   ReportDiagnostic(dispatch->getLocStart(), error) << receiver->record();
    454 }
    455 
    456 void DiagnosticsReporter::StackAllocatedDerivesGarbageCollected(
    457     RecordInfo* info,
    458     BasePoint* base) {
    459   ReportDiagnostic(base->spec().getLocStart(),
    460                    diag_stack_allocated_derives_gc_)
    461       << info->record() << base->info()->record();
    462 }
    463 
    464 void DiagnosticsReporter::ClassOverridesNew(
    465     RecordInfo* info,
    466     CXXMethodDecl* newop) {
    467   ReportDiagnostic(newop->getLocStart(), diag_class_overrides_new_)
    468       << info->record();
    469 }
    470 
    471 void DiagnosticsReporter::ClassDeclaresPureVirtualTrace(
    472     RecordInfo* info,
    473     CXXMethodDecl* trace) {
    474   ReportDiagnostic(trace->getLocStart(),
    475                    diag_class_declares_pure_virtual_trace_)
    476       << info->record();
    477 }
    478 
    479 void DiagnosticsReporter::LeftMostBaseMustBePolymorphic(
    480     RecordInfo* derived,
    481     CXXRecordDecl* base) {
    482   ReportDiagnostic(base->getLocStart(),
    483                    diag_left_most_base_must_be_polymorphic_)
    484       << base << derived->record();
    485 }
    486 
    487 void DiagnosticsReporter::BaseClassMustDeclareVirtualTrace(
    488     RecordInfo* derived,
    489     CXXRecordDecl* base) {
    490   ReportDiagnostic(base->getLocStart(),
    491                    diag_base_class_must_declare_virtual_trace_)
    492       << base << derived->record();
    493 }
    494 
    495 void DiagnosticsReporter::NoteManualDispatchMethod(CXXMethodDecl* dispatch) {
    496   ReportDiagnostic(dispatch->getLocStart(),
    497                    diag_manual_dispatch_method_note_)
    498       << dispatch;
    499 }
    500 
    501 void DiagnosticsReporter::NoteBaseRequiresTracing(BasePoint* base) {
    502   ReportDiagnostic(base->spec().getLocStart(),
    503                    diag_base_requires_tracing_note_)
    504       << base->info()->record();
    505 }
    506 
    507 void DiagnosticsReporter::NoteFieldRequiresTracing(
    508     RecordInfo* holder,
    509     FieldDecl* field) {
    510   NoteField(field, diag_field_requires_tracing_note_);
    511 }
    512 
    513 void DiagnosticsReporter::NoteFieldShouldNotBeTraced(
    514     RecordInfo* holder,
    515     FieldDecl* field) {
    516   NoteField(field, diag_field_should_not_be_traced_note_);
    517 }
    518 
    519 void DiagnosticsReporter::NotePartObjectContainsGCRoot(FieldPoint* point) {
    520   FieldDecl* field = point->field();
    521   ReportDiagnostic(field->getLocStart(),
    522                    diag_part_object_contains_gc_root_note_)
    523       << field << field->getParent();
    524 }
    525 
    526 void DiagnosticsReporter::NoteFieldContainsGCRoot(FieldPoint* point) {
    527   NoteField(point, diag_field_contains_gc_root_note_);
    528 }
    529 
    530 void DiagnosticsReporter::NoteUserDeclaredDestructor(CXXMethodDecl* dtor) {
    531   ReportDiagnostic(dtor->getLocStart(), diag_user_declared_destructor_note_);
    532 }
    533 
    534 void DiagnosticsReporter::NoteUserDeclaredFinalizer(CXXMethodDecl* dtor) {
    535   ReportDiagnostic(dtor->getLocStart(), diag_user_declared_finalizer_note_);
    536 }
    537 
    538 void DiagnosticsReporter::NoteBaseRequiresFinalization(BasePoint* base) {
    539   ReportDiagnostic(base->spec().getLocStart(),
    540                    diag_base_requires_finalization_note_)
    541       << base->info()->record();
    542 }
    543 
    544 void DiagnosticsReporter::NoteFieldRequiresFinalization(FieldPoint* point) {
    545   NoteField(point, diag_field_requires_finalization_note_);
    546 }
    547 
    548 void DiagnosticsReporter::NoteField(FieldPoint* point, unsigned note) {
    549   NoteField(point->field(), note);
    550 }
    551 
    552 void DiagnosticsReporter::NoteField(FieldDecl* field, unsigned note) {
    553   ReportDiagnostic(field->getLocStart(), note) << field;
    554 }
    555 
    556 void DiagnosticsReporter::NoteOverriddenNonVirtualTrace(
    557     CXXMethodDecl* overridden) {
    558   ReportDiagnostic(overridden->getLocStart(),
    559                    diag_overridden_non_virtual_trace_note_)
    560       << overridden;
    561 }
    562