// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "DiagnosticsReporter.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
namespace {
const char kClassMustLeftMostlyDeriveGC[] =
"[blink-gc] Class %0 must derive from GarbageCollected in the left-most position.";
const char kClassRequiresTraceMethod[] =
"[blink-gc] Class %0 requires a trace method.";
const char kBaseRequiresTracing[] =
"[blink-gc] Base class %0 of derived class %1 requires tracing.";
const char kBaseRequiresTracingNote[] =
"[blink-gc] Untraced base class %0 declared here:";
const char kFieldsRequireTracing[] =
"[blink-gc] Class %0 has untraced fields that require tracing.";
const char kFieldsImproperlyTraced[] =
"[blink-gc] Class %0 has untraced or not traceable fields.";
const char kFieldRequiresTracingNote[] =
"[blink-gc] Untraced field %0 declared here:";
const char kFieldShouldNotBeTracedNote[] =
"[blink-gc] Untraceable field %0 declared here:";
const char kClassContainsInvalidFields[] =
"[blink-gc] Class %0 contains invalid fields.";
const char kClassContainsGCRoot[] =
"[blink-gc] Class %0 contains GC root in field %1.";
const char kClassContainsGCRootRef[] =
"[blink-gc] Class %0 contains a reference to a GC root in field %1. Avoid "
"holding references to GC roots. This should generally not be needed.";
const char kFinalizerAccessesFinalizedField[] =
"[blink-gc] Finalizer %0 accesses potentially finalized field %1.";
const char kRawPtrToGCManagedClassNote[] =
"[blink-gc] Raw pointer field %0 to a GC managed class declared here:";
const char kRefPtrToGCManagedClassNote[] =
"[blink-gc] scoped_refptr field %0 to a GC managed class declared here:";
const char kReferencePtrToGCManagedClassNote[] =
"[blink-gc] Reference pointer field %0 to a GC managed class"
" declared here:";
const char kUniquePtrToGCManagedClassNote[] =
"[blink-gc] std::unique_ptr field %0 to a GC managed class declared here:";
const char kRawPtrToTraceableClassNote[] =
"[blink-gc] Raw pointer field %0 to a traceable class declared here:";
const char kRefPtrToTraceableClassNote[] =
"[blink-gc] scoped_refptr field %0 to a traceable class declared here:";
const char kReferencePtrToTraceableClassNote[] =
"[blink-gc] Reference pointer field %0 to a traceable class"
" declared here:";
const char kUniquePtrToTraceableClassNote[] =
"[blink-gc] std::unique_ptr field %0 to a traceable class declared here:";
const char kWeakPtrToGCManagedClass[] =
"[blink-gc] WeakPtr or WeakPtrFactory field %0 to a GC managed class %1 "
"declared here (use WeakCell or WeakCellFactory instead):";
const char kGCedField[] =
"[blink-gc] Using GC managed class %1 as field %0 is not allowed (Allocate "
"with MakeGarbageCollected and use Member or Persistent instead):";
const char kGCedVar[] =
"[blink-gc] Using GC managed class %1 as variable %0 is not allowed "
"(Allocate with MakeGarbageCollected and use raw pointer instead):";
const char kTaskRunnerInGCManagedClassNote[] =
"[blink-gc] TaskRunnerTimer field %0 used within a garbage collected "
"context. "
"Consider using HeapTaskRunnerTimer instead.";
const char kMojoRemoteInGCManagedClassNote[] =
"[blink-gc] mojo::Remote field %0 used within a garbage collected "
"context. "
"Consider using blink::HeapMojoRemote instead.";
const char kMojoReceiverInGCManagedClassNote[] =
"[blink-gc] mojo::Receiver field %0 used within a garbage collected "
"context. "
"Consider using blink::HeapMojoAssociatedRemote instead.";
const char kMojoAssociatedRemoteInGCManagedClassNote[] =
"[blink-gc] mojo::AssociatedRemote field %0 used within a garbage "
"collected context. "
"Consider using blink::HeapMojoAssociatedReceiver instead.";
const char kMojoAssociatedReceiverInGCManagedClassNote[] =
"[blink-gc] mojo::AssociatedReceiver field %0 used within a garbage "
"collected context. "
"Consider using blink::HeapMojoReceiver instead.";
const char kForbiddenFieldPartObjectClassNote[] =
"[blink-gc] From part object field %0 here:";
const char kMemberToGCUnmanagedClassNote[] =
"[blink-gc] Member field %0 to non-GC managed class declared here:";
const char kStackAllocatedFieldNote[] =
"[blink-gc] Stack-allocated field %0 declared here:";
const char kMemberInUnmanagedClassNote[] =
"[blink-gc] Member field %0 in unmanaged class declared here:";
const char kPtrToMemberInUnmanagedClassNote[] =
"[blink-gc] Pointer to Member field %0 in unmanaged class declared here:";
const char kPartObjectToGCDerivedClassNote[] =
"[blink-gc] Part-object field %0 to a GC derived class declared here:";
const char kPartObjectContainsGCRootNote[] =
"[blink-gc] Field %0 with embedded GC root in %1 declared here:";
const char kPartObjectContainsGCRootRefNote[] =
"[blink-gc] Field %0 with embedded reference to a GC root in %1 declared "
"here:";
const char kFieldContainsGCRootNote[] =
"[blink-gc] Field %0 defining a GC root declared here:";
const char kFieldContainsGCRootRefNote[] =
"[blink-gc] Field %0 defining reference to a GC root declared here:";
const char kOverriddenNonVirtualTrace[] =
"[blink-gc] Class %0 overrides non-virtual trace of base class %1.";
const char kOverriddenNonVirtualTraceNote[] =
"[blink-gc] Non-virtual trace method declared here:";
const char kMissingTraceDispatchMethod[] =
"[blink-gc] Class %0 is missing manual trace dispatch.";
const char kVirtualAndManualDispatch[] =
"[blink-gc] Class %0 contains or inherits virtual methods"
" but implements manual dispatching.";
const char kMissingTraceDispatch[] =
"[blink-gc] Missing dispatch to class %0 in manual trace dispatch.";
const char kMissingFinalizeDispatch[] =
"[blink-gc] Missing dispatch to class %0 in manual finalize dispatch.";
const char kFinalizedFieldNote[] =
"[blink-gc] Potentially finalized field %0 declared here:";
const char kManualDispatchMethodNote[] =
"[blink-gc] Manual dispatch %0 declared here:";
const char kStackAllocatedDerivesGarbageCollected[] =
"[blink-gc] Stack-allocated class %0 derives class %1"
" which is garbage collected.";
const char kClassOverridesNew[] =
"[blink-gc] Garbage collected class %0"
" is not permitted to override its new operator.";
const char kClassDeclaresPureVirtualTrace[] =
"[blink-gc] Garbage collected class %0"
" is not permitted to declare a pure-virtual trace method.";
const char kLeftMostBaseMustBePolymorphic[] =
"[blink-gc] Left-most base class %0 of derived class %1"
" must be polymorphic.";
const char kBaseClassMustDeclareVirtualTrace[] =
"[blink-gc] Left-most base class %0 of derived class %1"
" must define a virtual trace method.";
const char kClassMustCRTPItself[] =
"[blink-gc] GC base class %0 must be specialized with the derived class "
"%1.";
const char kIteratorToGCManagedCollectionNote[] =
"[blink-gc] Iterator field %0 to a GC managed collection declared here:";
const char kTraceMethodOfStackAllocatedParentNote[] =
"[blink-gc] The stack allocated class %0 provides an unnecessary "
"trace method:";
const char kMemberInStackAllocated[] =
"[blink-gc] Member field %0 in stack allocated class declared here (use "
"raw pointer or reference instead):";
const char kMemberOnStack[] =
"[blink-gc] Member variable %0 declared on stack here (use raw pointer or "
"reference instead):";
const char kAdditionalPadding[] =
"[blink-gc] Additional padding causes the sizeof(%0) to grow by %1. "
"Consider reordering fields.";
const char kTraceablePartObjectInUnmanaged[] =
"[blink-gc] Traceable part object field %0 found in unmanaged class:";
const char kUniquePtrUsedWithGC[] =
"[blink-gc] Disallowed use of %0 found; %1 is a garbage-collected type. "
"std::unique_ptr cannot hold garbage-collected objects.";
const char kOptionalDeclUsedWithGC[] =
"[blink-gc] Disallowed optional field or variable of type %0 found; %1 is "
"a "
"garbage-collected or traceable "
"type. Optional fields and variables cannot hold garbage-collected or "
"traceable objects.";
const char kOptionalNewExprUsedWithGC[] =
"[blink-gc] Disallowed new-expression of %0 found; %1 is a "
"garbage-collected or traceable "
"type. Optional fields cannot hold garbage-collected or traceable objects.";
const char kRawPtrOrRefDeclUsedWithGC[] =
"[blink-gc] Disallowed raw_ptr or raw_ref field or variable of type %0 "
"found; %1 is a "
"garbage-collected or traceable "
"type. Raw_ptr and raw_ref field and variable cannot hold "
"garbage-collected or "
"traceable objects.";
const char kRawPtrOrRefNewExprUsedWithGC[] =
"[blink-gc] Disallowed new-expression of %0 found; %1 is a "
"garbage-collected or traceable "
"type. Raw_ptr and raw_ref fields cannot hold garbage-collected or "
"traceable objects.";
const char kVariantUsedWithGC[] =
"[blink-gc] Disallowed construction of %0 found; %1 is a garbage-collected "
"type. Variant cannot hold garbage-collected objects.";
const char kCollectionOfGced[] =
"[blink-gc] Disallowed collection %0 found; %1 is a "
"garbage-collected "
"type. Use heap collections to hold garbage-collected objects.";
const char kCollectionOfMembers[] =
"[blink-gc] Disallowed collection %0 found; %1 is a "
"Member type. Use heap collections to hold Members.";
} // namespace
DiagnosticBuilder DiagnosticsReporter::ReportDiagnostic(
SourceLocation location,
unsigned diag_id) {
SourceManager& manager = instance_.getSourceManager();
FullSourceLoc full_loc(location, manager);
return diagnostic_.Report(full_loc, diag_id);
}
DiagnosticsReporter::DiagnosticsReporter(
clang::CompilerInstance& instance)
: instance_(instance),
diagnostic_(instance.getDiagnostics())
{
// Register warning/error messages.
diag_class_must_left_mostly_derive_gc_ = diagnostic_.getCustomDiagID(
getErrorLevel(), kClassMustLeftMostlyDeriveGC);
diag_class_requires_trace_method_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kClassRequiresTraceMethod);
diag_base_requires_tracing_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kBaseRequiresTracing);
diag_fields_require_tracing_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kFieldsRequireTracing);
diag_fields_improperly_traced_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kFieldsImproperlyTraced);
diag_class_contains_invalid_fields_ = diagnostic_.getCustomDiagID(
getErrorLevel(), kClassContainsInvalidFields);
diag_class_contains_gc_root_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kClassContainsGCRoot);
diag_class_contains_gc_root_ref_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kClassContainsGCRootRef);
diag_finalizer_accesses_finalized_field_ = diagnostic_.getCustomDiagID(
getErrorLevel(), kFinalizerAccessesFinalizedField);
diag_overridden_non_virtual_trace_ = diagnostic_.getCustomDiagID(
getErrorLevel(), kOverriddenNonVirtualTrace);
diag_missing_trace_dispatch_method_ = diagnostic_.getCustomDiagID(
getErrorLevel(), kMissingTraceDispatchMethod);
diag_virtual_and_manual_dispatch_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kVirtualAndManualDispatch);
diag_missing_trace_dispatch_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kMissingTraceDispatch);
diag_missing_finalize_dispatch_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kMissingFinalizeDispatch);
diag_stack_allocated_derives_gc_ = diagnostic_.getCustomDiagID(
getErrorLevel(), kStackAllocatedDerivesGarbageCollected);
diag_class_overrides_new_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kClassOverridesNew);
diag_class_declares_pure_virtual_trace_ = diagnostic_.getCustomDiagID(
getErrorLevel(), kClassDeclaresPureVirtualTrace);
diag_left_most_base_must_be_polymorphic_ = diagnostic_.getCustomDiagID(
getErrorLevel(), kLeftMostBaseMustBePolymorphic);
diag_base_class_must_declare_virtual_trace_ = diagnostic_.getCustomDiagID(
getErrorLevel(), kBaseClassMustDeclareVirtualTrace);
diag_class_must_crtp_itself_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kClassMustCRTPItself);
diag_iterator_to_gc_managed_collection_note_ = diagnostic_.getCustomDiagID(
getErrorLevel(), kIteratorToGCManagedCollectionNote);
diag_trace_method_of_stack_allocated_parent_ = diagnostic_.getCustomDiagID(
getErrorLevel(), kTraceMethodOfStackAllocatedParentNote);
diag_member_in_stack_allocated_class_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kMemberInStackAllocated);
diag_member_on_stack_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kMemberOnStack);
diag_additional_padding_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kAdditionalPadding);
diag_part_object_in_unmanaged_ = diagnostic_.getCustomDiagID(
getErrorLevel(), kTraceablePartObjectInUnmanaged);
diag_weak_ptr_to_gc_managed_class_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kWeakPtrToGCManagedClass);
diag_gced_field_ = diagnostic_.getCustomDiagID(getErrorLevel(), kGCedField);
diag_gced_var_ = diagnostic_.getCustomDiagID(getErrorLevel(), kGCedVar);
// Register note messages.
diag_base_requires_tracing_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kBaseRequiresTracingNote);
diag_field_requires_tracing_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kFieldRequiresTracingNote);
diag_field_should_not_be_traced_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kFieldShouldNotBeTracedNote);
diag_raw_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kRawPtrToGCManagedClassNote);
diag_ref_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote);
diag_reference_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kReferencePtrToGCManagedClassNote);
diag_unique_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kUniquePtrToGCManagedClassNote);
diag_task_runner_timer_in_gc_class_note = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kTaskRunnerInGCManagedClassNote);
diag_mojo_remote_in_gc_class_note = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kMojoRemoteInGCManagedClassNote);
diag_mojo_receiver_in_gc_class_note = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kMojoReceiverInGCManagedClassNote);
diag_mojo_associated_remote_in_gc_class_note = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kMojoAssociatedRemoteInGCManagedClassNote);
diag_mojo_associated_receiver_in_gc_class_note = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kMojoAssociatedReceiverInGCManagedClassNote);
diag_forbidden_field_part_object_class_note = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kForbiddenFieldPartObjectClassNote);
diag_member_to_gc_unmanaged_class_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kMemberToGCUnmanagedClassNote);
diag_stack_allocated_field_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kStackAllocatedFieldNote);
diag_member_in_unmanaged_class_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kMemberInUnmanagedClassNote);
diag_ptr_to_member_in_unmanaged_class_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kPtrToMemberInUnmanagedClassNote);
diag_part_object_to_gc_derived_class_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kPartObjectToGCDerivedClassNote);
diag_part_object_contains_gc_root_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kPartObjectContainsGCRootNote);
diag_part_object_contains_gc_root_ref_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kPartObjectContainsGCRootRefNote);
diag_field_contains_gc_root_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kFieldContainsGCRootNote);
diag_field_contains_gc_root_ref_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kFieldContainsGCRootRefNote);
diag_finalized_field_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kFinalizedFieldNote);
diag_overridden_non_virtual_trace_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kOverriddenNonVirtualTraceNote);
diag_manual_dispatch_method_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kManualDispatchMethodNote);
diag_raw_ptr_to_traceable_class_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kRawPtrToTraceableClassNote);
diag_ref_ptr_to_traceable_class_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kRefPtrToTraceableClassNote);
diag_reference_ptr_to_traceable_class_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kReferencePtrToTraceableClassNote);
diag_unique_ptr_to_traceable_class_note_ = diagnostic_.getCustomDiagID(
DiagnosticsEngine::Note, kUniquePtrToTraceableClassNote);
diag_unique_ptr_used_with_gc_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kUniquePtrUsedWithGC);
diag_optional_decl_used_with_gc_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kOptionalDeclUsedWithGC);
diag_optional_new_expr_used_with_gc_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kOptionalNewExprUsedWithGC);
diag_raw_ptr_or_ref_decl_used_with_gc_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kRawPtrOrRefDeclUsedWithGC);
diag_raw_ptr_or_ref_new_expr_used_with_gc_ = diagnostic_.getCustomDiagID(
getErrorLevel(), kRawPtrOrRefNewExprUsedWithGC);
diag_variant_used_with_gc_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kVariantUsedWithGC);
diag_collection_of_gced_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kCollectionOfGced);
diag_collection_of_members_ =
diagnostic_.getCustomDiagID(getErrorLevel(), kCollectionOfMembers);
}
bool DiagnosticsReporter::hasErrorOccurred() const
{
return diagnostic_.hasErrorOccurred();
}
DiagnosticsEngine::Level DiagnosticsReporter::getErrorLevel() const {
return diagnostic_.getWarningsAsErrors() ? DiagnosticsEngine::Error
: DiagnosticsEngine::Warning;
}
void DiagnosticsReporter::ClassMustLeftMostlyDeriveGC(
RecordInfo* info) {
ReportDiagnostic(info->record()->getInnerLocStart(),
diag_class_must_left_mostly_derive_gc_)
<< info->record();
}
void DiagnosticsReporter::ClassRequiresTraceMethod(RecordInfo* info) {
ReportDiagnostic(info->record()->getInnerLocStart(),
diag_class_requires_trace_method_)
<< info->record();
for (auto& base : info->GetBases())
if (base.second.NeedsTracing().IsNeeded())
NoteBaseRequiresTracing(&base.second);
for (auto& field : info->GetFields())
if (!field.second.IsProperlyTraced())
NoteFieldRequiresTracing(info, field.first);
}
void DiagnosticsReporter::BaseRequiresTracing(
RecordInfo* derived,
CXXMethodDecl* trace,
CXXRecordDecl* base) {
ReportDiagnostic(trace->getBeginLoc(), diag_base_requires_tracing_)
<< base << derived->record();
}
void DiagnosticsReporter::FieldsImproperlyTraced(
RecordInfo* info,
CXXMethodDecl* trace) {
// Only mention untraceable in header diagnostic if they appear.
unsigned diag = diag_fields_require_tracing_;
for (auto& field : info->GetFields()) {
if (field.second.IsInproperlyTraced()) {
diag = diag_fields_improperly_traced_;
break;
}
}
ReportDiagnostic(trace->getBeginLoc(), diag) << info->record();
for (auto& field : info->GetFields()) {
if (!field.second.IsProperlyTraced())
NoteFieldRequiresTracing(info, field.first);
if (field.second.IsInproperlyTraced())
NoteFieldShouldNotBeTraced(info, field.first);
}
}
void DiagnosticsReporter::ClassContainsInvalidFields(
RecordInfo* info,
const CheckFieldsVisitor::Errors& errors) {
ReportDiagnostic(info->record()->getBeginLoc(),
diag_class_contains_invalid_fields_)
<< info->record();
for (auto& error : errors) {
unsigned note;
if (error.second == CheckFieldsVisitor::kRawPtrToGCManaged) {
note = diag_raw_ptr_to_gc_managed_class_note_;
} else if (error.second == CheckFieldsVisitor::kRefPtrToGCManaged) {
note = diag_ref_ptr_to_gc_managed_class_note_;
} else if (error.second == CheckFieldsVisitor::kReferencePtrToGCManaged) {
note = diag_reference_ptr_to_gc_managed_class_note_;
} else if (error.second == CheckFieldsVisitor::kUniquePtrToGCManaged) {
note = diag_unique_ptr_to_gc_managed_class_note_;
} else if (error.second == CheckFieldsVisitor::kMemberToGCUnmanaged) {
note = diag_member_to_gc_unmanaged_class_note_;
} else if (error.second == CheckFieldsVisitor::kMemberInUnmanaged) {
note = diag_member_in_unmanaged_class_note_;
} else if (error.second == CheckFieldsVisitor::kPtrToMemberInUnmanaged) {
note = diag_ptr_to_member_in_unmanaged_class_note_;
} else if (error.second == CheckFieldsVisitor::kPtrFromHeapToStack) {
note = diag_stack_allocated_field_note_;
} else if (error.second == CheckFieldsVisitor::kGCDerivedPartObject) {
note = diag_part_object_to_gc_derived_class_note_;
} else if (error.second == CheckFieldsVisitor::kIteratorToGCManaged) {
note = diag_iterator_to_gc_managed_collection_note_;
} else if (error.second == CheckFieldsVisitor::kMemberInStackAllocated) {
note = diag_member_in_stack_allocated_class_;
} else if (error.second ==
CheckFieldsVisitor::kTraceablePartObjectInUnmanaged) {
note = diag_part_object_in_unmanaged_;
} else if (error.second == CheckFieldsVisitor::kRawPtrToTraceable) {
note = diag_raw_ptr_to_traceable_class_note_;
} else if (error.second == CheckFieldsVisitor::kRefPtrToTraceable) {
note = diag_ref_ptr_to_traceable_class_note_;
} else if (error.second == CheckFieldsVisitor::kReferencePtrToTraceable) {
note = diag_reference_ptr_to_traceable_class_note_;
} else if (error.second == CheckFieldsVisitor::kUniquePtrToTraceable) {
note = diag_unique_ptr_to_traceable_class_note_;
} else {
llvm_unreachable("Unknown field error.");
}
NoteField(error.first, note);
}
}
void DiagnosticsReporter::ClassContainsGCRoots(
RecordInfo* info,
const CheckGCRootsVisitor::Errors& errors) {
for (auto& error : errors) {
FieldPoint* point = nullptr;
for (FieldPoint* path : error) {
if (!point) {
point = path;
ReportDiagnostic(info->record()->getBeginLoc(),
diag_class_contains_gc_root_)
<< info->record() << point->field();
continue;
}
NotePartObjectContainsGCRoot(point);
point = path;
}
NoteFieldContainsGCRoot(point);
}
}
void DiagnosticsReporter::ClassContainsGCRootRefs(
RecordInfo* info,
const CheckGCRootsVisitor::Errors& errors) {
for (auto& error : errors) {
FieldPoint* point = nullptr;
for (FieldPoint* path : error) {
if (!point) {
point = path;
ReportDiagnostic(info->record()->getBeginLoc(),
diag_class_contains_gc_root_ref_)
<< info->record() << point->field();
continue;
}
NotePartObjectContainsGCRootRef(point);
point = path;
}
NoteFieldContainsGCRootRef(point);
}
}
void DiagnosticsReporter::ClassContainsForbiddenFields(
RecordInfo* info,
const CheckForbiddenFieldsVisitor::Errors& errors) {
ReportDiagnostic(info->record()->getBeginLoc(),
diag_class_contains_invalid_fields_)
<< info->record();
for (const auto& error : errors) {
for (FieldPoint* field : error.first) {
if (field == error.first.back()) {
break;
}
NoteField(field, diag_forbidden_field_part_object_class_note);
}
unsigned note;
if (error.second ==
CheckForbiddenFieldsVisitor::Error::kTaskRunnerInGCManaged) {
note = diag_task_runner_timer_in_gc_class_note;
} else if (error.second ==
CheckForbiddenFieldsVisitor::Error::kMojoRemoteInGCManaged) {
note = diag_mojo_remote_in_gc_class_note;
} else if (error.second ==
CheckForbiddenFieldsVisitor::Error::kMojoReceiverInGCManaged) {
note = diag_mojo_receiver_in_gc_class_note;
} else if (error.second == CheckForbiddenFieldsVisitor::Error::
kMojoAssociatedRemoteInGCManaged) {
note = diag_mojo_associated_remote_in_gc_class_note;
} else if (error.second == CheckForbiddenFieldsVisitor::Error::
kMojoAssociatedReceiverInGCManaged) {
note = diag_mojo_associated_receiver_in_gc_class_note;
} else {
llvm_unreachable("Unknown field error.");
}
NoteField(error.first.back(), note);
}
}
void DiagnosticsReporter::FinalizerAccessesFinalizedFields(
CXXMethodDecl* dtor,
const CheckFinalizerVisitor::Errors& errors) {
for (auto& error : errors) {
ReportDiagnostic(error.member->getBeginLoc(),
diag_finalizer_accesses_finalized_field_)
<< dtor << error.field->field();
NoteField(error.field, diag_finalized_field_note_);
}
}
void DiagnosticsReporter::OverriddenNonVirtualTrace(
RecordInfo* info,
CXXMethodDecl* trace,
CXXMethodDecl* overridden) {
ReportDiagnostic(trace->getBeginLoc(), diag_overridden_non_virtual_trace_)
<< info->record() << overridden->getParent();
NoteOverriddenNonVirtualTrace(overridden);
}
void DiagnosticsReporter::MissingTraceDispatchMethod(RecordInfo* info) {
ReportMissingDispatchMethod(info, diag_missing_trace_dispatch_method_);
}
void DiagnosticsReporter::ReportMissingDispatchMethod(
RecordInfo* info,
unsigned error) {
ReportDiagnostic(info->record()->getInnerLocStart(), error)
<< info->record();
}
void DiagnosticsReporter::VirtualAndManualDispatch(
RecordInfo* info,
CXXMethodDecl* dispatch) {
ReportDiagnostic(info->record()->getInnerLocStart(),
diag_virtual_and_manual_dispatch_)
<< info->record();
NoteManualDispatchMethod(dispatch);
}
void DiagnosticsReporter::MissingTraceDispatch(
const FunctionDecl* dispatch,
RecordInfo* receiver) {
ReportMissingDispatch(dispatch, receiver, diag_missing_trace_dispatch_);
}
void DiagnosticsReporter::MissingFinalizeDispatch(
const FunctionDecl* dispatch,
RecordInfo* receiver) {
ReportMissingDispatch(dispatch, receiver, diag_missing_finalize_dispatch_);
}
void DiagnosticsReporter::ReportMissingDispatch(
const FunctionDecl* dispatch,
RecordInfo* receiver,
unsigned error) {
ReportDiagnostic(dispatch->getBeginLoc(), error) << receiver->record();
}
void DiagnosticsReporter::StackAllocatedDerivesGarbageCollected(
RecordInfo* info,
BasePoint* base) {
ReportDiagnostic(base->spec().getBeginLoc(), diag_stack_allocated_derives_gc_)
<< info->record() << base->info()->record();
}
void DiagnosticsReporter::ClassOverridesNew(
RecordInfo* info,
CXXMethodDecl* newop) {
ReportDiagnostic(newop->getBeginLoc(), diag_class_overrides_new_)
<< info->record();
}
void DiagnosticsReporter::ClassDeclaresPureVirtualTrace(
RecordInfo* info,
CXXMethodDecl* trace) {
ReportDiagnostic(trace->getBeginLoc(),
diag_class_declares_pure_virtual_trace_)
<< info->record();
}
void DiagnosticsReporter::LeftMostBaseMustBePolymorphic(
RecordInfo* derived,
CXXRecordDecl* base) {
ReportDiagnostic(base->getBeginLoc(),
diag_left_most_base_must_be_polymorphic_)
<< base << derived->record();
}
void DiagnosticsReporter::BaseClassMustDeclareVirtualTrace(
RecordInfo* derived,
CXXRecordDecl* base) {
ReportDiagnostic(base->getBeginLoc(),
diag_base_class_must_declare_virtual_trace_)
<< base << derived->record();
}
void DiagnosticsReporter::ClassMustCRTPItself(
const RecordInfo* derived,
const CXXRecordDecl* base,
const CXXBaseSpecifier* base_spec) {
ReportDiagnostic(base_spec->getBeginLoc(), diag_class_must_crtp_itself_)
<< base << derived->record();
}
void DiagnosticsReporter::TraceMethodForStackAllocatedClass(
RecordInfo* info,
CXXMethodDecl* trace) {
ReportDiagnostic(trace->getBeginLoc(),
diag_trace_method_of_stack_allocated_parent_)
<< info->record();
}
void DiagnosticsReporter::NoteManualDispatchMethod(CXXMethodDecl* dispatch) {
ReportDiagnostic(dispatch->getBeginLoc(), diag_manual_dispatch_method_note_)
<< dispatch;
}
void DiagnosticsReporter::NoteBaseRequiresTracing(BasePoint* base) {
ReportDiagnostic(base->spec().getBeginLoc(), diag_base_requires_tracing_note_)
<< base->info()->record();
}
void DiagnosticsReporter::NoteFieldRequiresTracing(
RecordInfo* holder,
FieldDecl* field) {
NoteField(field, diag_field_requires_tracing_note_);
}
void DiagnosticsReporter::NoteFieldShouldNotBeTraced(
RecordInfo* holder,
FieldDecl* field) {
NoteField(field, diag_field_should_not_be_traced_note_);
}
void DiagnosticsReporter::NotePartObjectContainsGCRoot(FieldPoint* point) {
FieldDecl* field = point->field();
ReportDiagnostic(field->getBeginLoc(),
diag_part_object_contains_gc_root_note_)
<< field << field->getParent();
}
void DiagnosticsReporter::NotePartObjectContainsGCRootRef(FieldPoint* point) {
FieldDecl* field = point->field();
ReportDiagnostic(field->getBeginLoc(),
diag_part_object_contains_gc_root_ref_note_)
<< field << field->getParent();
}
void DiagnosticsReporter::NoteFieldContainsGCRoot(FieldPoint* point) {
NoteField(point, diag_field_contains_gc_root_note_);
}
void DiagnosticsReporter::NoteFieldContainsGCRootRef(FieldPoint* point) {
NoteField(point, diag_field_contains_gc_root_ref_note_);
}
void DiagnosticsReporter::NoteField(FieldPoint* point, unsigned note) {
NoteField(point->field(), note);
}
void DiagnosticsReporter::NoteField(FieldDecl* field, unsigned note) {
ReportDiagnostic(field->getBeginLoc(), note) << field;
}
void DiagnosticsReporter::NoteOverriddenNonVirtualTrace(
CXXMethodDecl* overridden) {
ReportDiagnostic(overridden->getBeginLoc(),
diag_overridden_non_virtual_trace_note_)
<< overridden;
}
void DiagnosticsReporter::UniquePtrUsedWithGC(
const clang::Expr* expr,
const clang::FunctionDecl* bad_function,
const clang::CXXRecordDecl* gc_type) {
ReportDiagnostic(expr->getBeginLoc(), diag_unique_ptr_used_with_gc_)
<< bad_function << gc_type << expr->getSourceRange();
}
void DiagnosticsReporter::OptionalDeclUsedWithGC(
const clang::Decl* decl,
const clang::CXXRecordDecl* optional,
const clang::CXXRecordDecl* gc_type) {
ReportDiagnostic(decl->getBeginLoc(), diag_optional_decl_used_with_gc_)
<< optional << gc_type << decl->getSourceRange();
}
void DiagnosticsReporter::OptionalNewExprUsedWithGC(
const clang::Expr* expr,
const clang::CXXRecordDecl* optional,
const clang::CXXRecordDecl* gc_type) {
ReportDiagnostic(expr->getBeginLoc(), diag_optional_new_expr_used_with_gc_)
<< optional << gc_type << expr->getSourceRange();
}
void DiagnosticsReporter::RawPtrOrRefDeclUsedWithGC(
const clang::Decl* decl,
const clang::CXXRecordDecl* optional,
const clang::CXXRecordDecl* gc_type) {
ReportDiagnostic(decl->getBeginLoc(), diag_raw_ptr_or_ref_decl_used_with_gc_)
<< optional << gc_type << decl->getSourceRange();
}
void DiagnosticsReporter::RawPtrOrRefNewExprUsedWithGC(
const clang::Expr* expr,
const clang::CXXRecordDecl* optional,
const clang::CXXRecordDecl* gc_type) {
ReportDiagnostic(expr->getBeginLoc(),
diag_raw_ptr_or_ref_new_expr_used_with_gc_)
<< optional << gc_type << expr->getSourceRange();
}
void DiagnosticsReporter::VariantUsedWithGC(
const clang::Expr* expr,
const clang::CXXRecordDecl* variant,
const clang::CXXRecordDecl* gc_type) {
ReportDiagnostic(expr->getBeginLoc(), diag_variant_used_with_gc_)
<< variant << gc_type << expr->getSourceRange();
}
void DiagnosticsReporter::CollectionOfGCed(
const clang::Decl* decl,
const clang::CXXRecordDecl* collection,
const clang::CXXRecordDecl* gc_type) {
ReportDiagnostic(decl->getBeginLoc(), diag_collection_of_gced_)
<< collection << gc_type << decl->getSourceRange();
}
void DiagnosticsReporter::CollectionOfGCed(
const clang::Expr* expr,
const clang::CXXRecordDecl* collection,
const clang::CXXRecordDecl* gc_type) {
ReportDiagnostic(expr->getBeginLoc(), diag_collection_of_gced_)
<< collection << gc_type << expr->getSourceRange();
}
void DiagnosticsReporter::CollectionOfMembers(
const clang::Decl* decl,
const clang::CXXRecordDecl* collection,
const clang::CXXRecordDecl* member) {
ReportDiagnostic(decl->getBeginLoc(), diag_collection_of_members_)
<< collection << member << decl->getSourceRange();
}
void DiagnosticsReporter::CollectionOfMembers(
const clang::Expr* expr,
const clang::CXXRecordDecl* collection,
const clang::CXXRecordDecl* member) {
ReportDiagnostic(expr->getBeginLoc(), diag_collection_of_members_)
<< collection << member << expr->getSourceRange();
}
void DiagnosticsReporter::MemberOnStack(const clang::VarDecl* var) {
ReportDiagnostic(var->getBeginLoc(), diag_member_on_stack_)
<< var->getName() << var->getSourceRange();
}
void DiagnosticsReporter::AdditionalPadding(const clang::RecordDecl* record,
size_t padding_size) {
ReportDiagnostic(record->getBeginLoc(), diag_additional_padding_)
<< record->getName() << padding_size << record->getSourceRange();
}
void DiagnosticsReporter::WeakPtrToGCed(const clang::Decl* decl,
const clang::CXXRecordDecl* weak_ptr,
const clang::CXXRecordDecl* gc_type) {
ReportDiagnostic(decl->getBeginLoc(), diag_weak_ptr_to_gc_managed_class_)
<< weak_ptr << gc_type << decl->getSourceRange();
}
void DiagnosticsReporter::GCedField(const clang::FieldDecl* field,
const clang::CXXRecordDecl* gctype) {
ReportDiagnostic(field->getBeginLoc(), diag_gced_field_)
<< field << gctype << field->getSourceRange();
}
void DiagnosticsReporter::GCedVar(const clang::VarDecl* var,
const clang::CXXRecordDecl* gctype) {
ReportDiagnostic(var->getBeginLoc(), diag_gced_var_)
<< var << gctype << var->getSourceRange();
}