| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "BlinkGCPluginConsumer.h" | 5 #include "BlinkGCPluginConsumer.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <set> | 8 #include <set> |
| 9 | 9 |
| 10 #include "CheckDispatchVisitor.h" | 10 #include "CheckDispatchVisitor.h" |
| 11 #include "CheckFieldsVisitor.h" |
| 12 #include "CheckFinalizerVisitor.h" |
| 13 #include "CheckGCRootsVisitor.h" |
| 11 #include "CheckTraceVisitor.h" | 14 #include "CheckTraceVisitor.h" |
| 12 #include "CollectVisitor.h" | 15 #include "CollectVisitor.h" |
| 13 #include "JsonWriter.h" | 16 #include "JsonWriter.h" |
| 14 #include "RecordInfo.h" | 17 #include "RecordInfo.h" |
| 15 #include "clang/AST/RecursiveASTVisitor.h" | 18 #include "clang/AST/RecursiveASTVisitor.h" |
| 16 #include "clang/Sema/Sema.h" | 19 #include "clang/Sema/Sema.h" |
| 17 | 20 |
| 18 using namespace clang; | 21 using namespace clang; |
| 19 | 22 |
| 20 namespace { | 23 namespace { |
| 21 | 24 |
| 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 // Use a local RAV implementation to simply collect all FunctionDecls marked for | 25 // Use a local RAV implementation to simply collect all FunctionDecls marked for |
| 153 // late template parsing. This happens with the flag -fdelayed-template-parsing, | 26 // late template parsing. This happens with the flag -fdelayed-template-parsing, |
| 154 // which is on by default in MSVC-compatible mode. | 27 // which is on by default in MSVC-compatible mode. |
| 155 std::set<FunctionDecl*> GetLateParsedFunctionDecls(TranslationUnitDecl* decl) { | 28 std::set<FunctionDecl*> GetLateParsedFunctionDecls(TranslationUnitDecl* decl) { |
| 156 struct Visitor : public RecursiveASTVisitor<Visitor> { | 29 struct Visitor : public RecursiveASTVisitor<Visitor> { |
| 157 bool VisitFunctionDecl(FunctionDecl* function_decl) { | 30 bool VisitFunctionDecl(FunctionDecl* function_decl) { |
| 158 if (function_decl->isLateTemplateParsed()) | 31 if (function_decl->isLateTemplateParsed()) |
| 159 late_parsed_decls.insert(function_decl); | 32 late_parsed_decls.insert(function_decl); |
| 160 return true; | 33 return true; |
| 161 } | 34 } |
| (...skipping 24 matching lines...) Expand all Loading... |
| 186 EmptyStmtVisitor() : empty_(true) {} | 59 EmptyStmtVisitor() : empty_(true) {} |
| 187 bool empty_; | 60 bool empty_; |
| 188 }; | 61 }; |
| 189 | 62 |
| 190 } // namespace | 63 } // namespace |
| 191 | 64 |
| 192 BlinkGCPluginConsumer::BlinkGCPluginConsumer( | 65 BlinkGCPluginConsumer::BlinkGCPluginConsumer( |
| 193 clang::CompilerInstance& instance, | 66 clang::CompilerInstance& instance, |
| 194 const BlinkGCPluginOptions& options) | 67 const BlinkGCPluginOptions& options) |
| 195 : instance_(instance), | 68 : instance_(instance), |
| 196 diagnostic_(instance.getDiagnostics()), | 69 reporter_(instance), |
| 197 options_(options), | 70 options_(options), |
| 198 json_(0) { | 71 json_(0) { |
| 199 // Only check structures in the blink and WebKit namespaces. | 72 // Only check structures in the blink and WebKit namespaces. |
| 200 options_.checked_namespaces.insert("blink"); | 73 options_.checked_namespaces.insert("blink"); |
| 201 | 74 |
| 202 // Ignore GC implementation files. | 75 // Ignore GC implementation files. |
| 203 options_.ignored_directories.push_back("/heap/"); | 76 options_.ignored_directories.push_back("/heap/"); |
| 204 | |
| 205 // Register warning/error messages. | |
| 206 diag_class_must_left_mostly_derive_gc_ = diagnostic_.getCustomDiagID( | |
| 207 getErrorLevel(), kClassMustLeftMostlyDeriveGC); | |
| 208 diag_class_requires_trace_method_ = | |
| 209 diagnostic_.getCustomDiagID(getErrorLevel(), kClassRequiresTraceMethod); | |
| 210 diag_base_requires_tracing_ = | |
| 211 diagnostic_.getCustomDiagID(getErrorLevel(), kBaseRequiresTracing); | |
| 212 diag_fields_require_tracing_ = | |
| 213 diagnostic_.getCustomDiagID(getErrorLevel(), kFieldsRequireTracing); | |
| 214 diag_class_contains_invalid_fields_ = diagnostic_.getCustomDiagID( | |
| 215 getErrorLevel(), kClassContainsInvalidFields); | |
| 216 diag_class_contains_gc_root_ = | |
| 217 diagnostic_.getCustomDiagID(getErrorLevel(), kClassContainsGCRoot); | |
| 218 diag_class_requires_finalization_ = diagnostic_.getCustomDiagID( | |
| 219 getErrorLevel(), kClassRequiresFinalization); | |
| 220 diag_class_does_not_require_finalization_ = diagnostic_.getCustomDiagID( | |
| 221 DiagnosticsEngine::Warning, kClassDoesNotRequireFinalization); | |
| 222 diag_finalizer_accesses_finalized_field_ = diagnostic_.getCustomDiagID( | |
| 223 getErrorLevel(), kFinalizerAccessesFinalizedField); | |
| 224 diag_finalizer_eagerly_finalized_field_ = diagnostic_.getCustomDiagID( | |
| 225 getErrorLevel(), kFinalizerAccessesEagerlyFinalizedField); | |
| 226 diag_overridden_non_virtual_trace_ = diagnostic_.getCustomDiagID( | |
| 227 getErrorLevel(), kOverriddenNonVirtualTrace); | |
| 228 diag_missing_trace_dispatch_method_ = diagnostic_.getCustomDiagID( | |
| 229 getErrorLevel(), kMissingTraceDispatchMethod); | |
| 230 diag_missing_finalize_dispatch_method_ = diagnostic_.getCustomDiagID( | |
| 231 getErrorLevel(), kMissingFinalizeDispatchMethod); | |
| 232 diag_virtual_and_manual_dispatch_ = | |
| 233 diagnostic_.getCustomDiagID(getErrorLevel(), kVirtualAndManualDispatch); | |
| 234 diag_missing_trace_dispatch_ = | |
| 235 diagnostic_.getCustomDiagID(getErrorLevel(), kMissingTraceDispatch); | |
| 236 diag_missing_finalize_dispatch_ = | |
| 237 diagnostic_.getCustomDiagID(getErrorLevel(), kMissingFinalizeDispatch); | |
| 238 diag_derives_non_stack_allocated_ = | |
| 239 diagnostic_.getCustomDiagID(getErrorLevel(), kDerivesNonStackAllocated); | |
| 240 diag_class_overrides_new_ = | |
| 241 diagnostic_.getCustomDiagID(getErrorLevel(), kClassOverridesNew); | |
| 242 diag_class_declares_pure_virtual_trace_ = diagnostic_.getCustomDiagID( | |
| 243 getErrorLevel(), kClassDeclaresPureVirtualTrace); | |
| 244 diag_left_most_base_must_be_polymorphic_ = diagnostic_.getCustomDiagID( | |
| 245 getErrorLevel(), kLeftMostBaseMustBePolymorphic); | |
| 246 diag_base_class_must_declare_virtual_trace_ = diagnostic_.getCustomDiagID( | |
| 247 getErrorLevel(), kBaseClassMustDeclareVirtualTrace); | |
| 248 | |
| 249 // Register note messages. | |
| 250 diag_base_requires_tracing_note_ = diagnostic_.getCustomDiagID( | |
| 251 DiagnosticsEngine::Note, kBaseRequiresTracingNote); | |
| 252 diag_field_requires_tracing_note_ = diagnostic_.getCustomDiagID( | |
| 253 DiagnosticsEngine::Note, kFieldRequiresTracingNote); | |
| 254 diag_raw_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( | |
| 255 DiagnosticsEngine::Note, kRawPtrToGCManagedClassNote); | |
| 256 diag_ref_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( | |
| 257 DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote); | |
| 258 diag_reference_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( | |
| 259 DiagnosticsEngine::Note, kReferencePtrToGCManagedClassNote); | |
| 260 diag_own_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( | |
| 261 DiagnosticsEngine::Note, kOwnPtrToGCManagedClassNote); | |
| 262 diag_member_to_gc_unmanaged_class_note_ = diagnostic_.getCustomDiagID( | |
| 263 DiagnosticsEngine::Note, kMemberToGCUnmanagedClassNote); | |
| 264 diag_stack_allocated_field_note_ = diagnostic_.getCustomDiagID( | |
| 265 DiagnosticsEngine::Note, kStackAllocatedFieldNote); | |
| 266 diag_member_in_unmanaged_class_note_ = diagnostic_.getCustomDiagID( | |
| 267 DiagnosticsEngine::Note, kMemberInUnmanagedClassNote); | |
| 268 diag_part_object_to_gc_derived_class_note_ = diagnostic_.getCustomDiagID( | |
| 269 DiagnosticsEngine::Note, kPartObjectToGCDerivedClassNote); | |
| 270 diag_part_object_contains_gc_root_note_ = diagnostic_.getCustomDiagID( | |
| 271 DiagnosticsEngine::Note, kPartObjectContainsGCRootNote); | |
| 272 diag_field_contains_gc_root_note_ = diagnostic_.getCustomDiagID( | |
| 273 DiagnosticsEngine::Note, kFieldContainsGCRootNote); | |
| 274 diag_finalized_field_note_ = diagnostic_.getCustomDiagID( | |
| 275 DiagnosticsEngine::Note, kFinalizedFieldNote); | |
| 276 diag_eagerly_finalized_field_note_ = diagnostic_.getCustomDiagID( | |
| 277 DiagnosticsEngine::Note, kEagerlyFinalizedFieldNote); | |
| 278 diag_user_declared_destructor_note_ = diagnostic_.getCustomDiagID( | |
| 279 DiagnosticsEngine::Note, kUserDeclaredDestructorNote); | |
| 280 diag_user_declared_finalizer_note_ = diagnostic_.getCustomDiagID( | |
| 281 DiagnosticsEngine::Note, kUserDeclaredFinalizerNote); | |
| 282 diag_base_requires_finalization_note_ = diagnostic_.getCustomDiagID( | |
| 283 DiagnosticsEngine::Note, kBaseRequiresFinalizationNote); | |
| 284 diag_field_requires_finalization_note_ = diagnostic_.getCustomDiagID( | |
| 285 DiagnosticsEngine::Note, kFieldRequiresFinalizationNote); | |
| 286 diag_overridden_non_virtual_trace_note_ = diagnostic_.getCustomDiagID( | |
| 287 DiagnosticsEngine::Note, kOverriddenNonVirtualTraceNote); | |
| 288 diag_manual_dispatch_method_note_ = diagnostic_.getCustomDiagID( | |
| 289 DiagnosticsEngine::Note, kManualDispatchMethodNote); | |
| 290 } | 77 } |
| 291 | 78 |
| 292 void BlinkGCPluginConsumer::HandleTranslationUnit(ASTContext& context) { | 79 void BlinkGCPluginConsumer::HandleTranslationUnit(ASTContext& context) { |
| 293 // Don't run the plugin if the compilation unit is already invalid. | 80 // Don't run the plugin if the compilation unit is already invalid. |
| 294 if (diagnostic_.hasErrorOccurred()) | 81 if (reporter_.hasErrorOccurred()) |
| 295 return; | 82 return; |
| 296 | 83 |
| 297 ParseFunctionTemplates(context.getTranslationUnitDecl()); | 84 ParseFunctionTemplates(context.getTranslationUnitDecl()); |
| 298 | 85 |
| 299 CollectVisitor visitor; | 86 CollectVisitor visitor; |
| 300 visitor.TraverseDecl(context.getTranslationUnitDecl()); | 87 visitor.TraverseDecl(context.getTranslationUnitDecl()); |
| 301 | 88 |
| 302 if (options_.dump_graph) { | 89 if (options_.dump_graph) { |
| 303 std::error_code err; | 90 std::error_code err; |
| 304 // TODO: Make createDefaultOutputFile or a shorter createOutputFile work. | 91 // TODO: Make createDefaultOutputFile or a shorter createOutputFile work. |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 386 } | 173 } |
| 387 | 174 |
| 388 void BlinkGCPluginConsumer::CheckClass(RecordInfo* info) { | 175 void BlinkGCPluginConsumer::CheckClass(RecordInfo* info) { |
| 389 if (!info) | 176 if (!info) |
| 390 return; | 177 return; |
| 391 | 178 |
| 392 // Check consistency of stack-allocated hierarchies. | 179 // Check consistency of stack-allocated hierarchies. |
| 393 if (info->IsStackAllocated()) { | 180 if (info->IsStackAllocated()) { |
| 394 for (auto& base : info->GetBases()) | 181 for (auto& base : info->GetBases()) |
| 395 if (!base.second.info()->IsStackAllocated()) | 182 if (!base.second.info()->IsStackAllocated()) |
| 396 ReportDerivesNonStackAllocated(info, &base.second); | 183 reporter_.DerivesNonStackAllocated(info, &base.second); |
| 397 } | 184 } |
| 398 | 185 |
| 399 if (CXXMethodDecl* trace = info->GetTraceMethod()) { | 186 if (CXXMethodDecl* trace = info->GetTraceMethod()) { |
| 400 if (trace->isPure()) | 187 if (trace->isPure()) |
| 401 ReportClassDeclaresPureVirtualTrace(info, trace); | 188 reporter_.ClassDeclaresPureVirtualTrace(info, trace); |
| 402 } else if (info->RequiresTraceMethod()) { | 189 } else if (info->RequiresTraceMethod()) { |
| 403 ReportClassRequiresTraceMethod(info); | 190 reporter_.ClassRequiresTraceMethod(info); |
| 404 } | 191 } |
| 405 | 192 |
| 406 // Check polymorphic classes that are GC-derived or have a trace method. | 193 // Check polymorphic classes that are GC-derived or have a trace method. |
| 407 if (info->record()->hasDefinition() && info->record()->isPolymorphic()) { | 194 if (info->record()->hasDefinition() && info->record()->isPolymorphic()) { |
| 408 // TODO: Check classes that inherit a trace method. | 195 // TODO: Check classes that inherit a trace method. |
| 409 CXXMethodDecl* trace = info->GetTraceMethod(); | 196 CXXMethodDecl* trace = info->GetTraceMethod(); |
| 410 if (trace || info->IsGCDerived()) | 197 if (trace || info->IsGCDerived()) |
| 411 CheckPolymorphicClass(info, trace); | 198 CheckPolymorphicClass(info, trace); |
| 412 } | 199 } |
| 413 | 200 |
| 414 { | 201 { |
| 415 CheckFieldsVisitor visitor(options_); | 202 CheckFieldsVisitor visitor; |
| 416 if (visitor.ContainsInvalidFields(info)) | 203 if (visitor.ContainsInvalidFields(info)) |
| 417 ReportClassContainsInvalidFields(info, visitor.invalid_fields()); | 204 reporter_.ClassContainsInvalidFields(info, visitor.invalid_fields()); |
| 418 } | 205 } |
| 419 | 206 |
| 420 if (info->IsGCDerived()) { | 207 if (info->IsGCDerived()) { |
| 421 if (!info->IsGCMixin()) { | 208 if (!info->IsGCMixin()) { |
| 422 CheckLeftMostDerived(info); | 209 CheckLeftMostDerived(info); |
| 423 CheckDispatch(info); | 210 CheckDispatch(info); |
| 424 if (CXXMethodDecl* newop = info->DeclaresNewOperator()) | 211 if (CXXMethodDecl* newop = info->DeclaresNewOperator()) |
| 425 if (!Config::IsIgnoreAnnotated(newop)) | 212 if (!Config::IsIgnoreAnnotated(newop)) |
| 426 ReportClassOverridesNew(info, newop); | 213 reporter_.ClassOverridesNew(info, newop); |
| 427 } | 214 } |
| 428 | 215 |
| 429 { | 216 { |
| 430 CheckGCRootsVisitor visitor; | 217 CheckGCRootsVisitor visitor; |
| 431 if (visitor.ContainsGCRoots(info)) | 218 if (visitor.ContainsGCRoots(info)) |
| 432 ReportClassContainsGCRoots(info, visitor.gc_roots()); | 219 reporter_.ClassContainsGCRoots(info, visitor.gc_roots()); |
| 433 } | 220 } |
| 434 | 221 |
| 435 if (info->NeedsFinalization()) | 222 if (info->NeedsFinalization()) |
| 436 CheckFinalization(info); | 223 CheckFinalization(info); |
| 437 | 224 |
| 438 if (options_.warn_unneeded_finalizer && info->IsGCFinalized()) | 225 if (options_.warn_unneeded_finalizer && info->IsGCFinalized()) |
| 439 CheckUnneededFinalization(info); | 226 CheckUnneededFinalization(info); |
| 440 } | 227 } |
| 441 | 228 |
| 442 DumpClass(info); | 229 DumpClass(info); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 506 it = left_most->bases_begin(); | 293 it = left_most->bases_begin(); |
| 507 } | 294 } |
| 508 | 295 |
| 509 if (RecordInfo* left_most_info = cache_.Lookup(left_most)) { | 296 if (RecordInfo* left_most_info = cache_.Lookup(left_most)) { |
| 510 // Check condition (1): | 297 // Check condition (1): |
| 511 if (trace && trace->isVirtual()) { | 298 if (trace && trace->isVirtual()) { |
| 512 if (CXXMethodDecl* trace = left_most_info->GetTraceMethod()) { | 299 if (CXXMethodDecl* trace = left_most_info->GetTraceMethod()) { |
| 513 if (trace->isVirtual()) | 300 if (trace->isVirtual()) |
| 514 return; | 301 return; |
| 515 } | 302 } |
| 516 ReportBaseClassMustDeclareVirtualTrace(info, left_most); | 303 reporter_.BaseClassMustDeclareVirtualTrace(info, left_most); |
| 517 return; | 304 return; |
| 518 } | 305 } |
| 519 | 306 |
| 520 // Check condition (2): | 307 // Check condition (2): |
| 521 if (DeclaresVirtualMethods(left_most)) | 308 if (DeclaresVirtualMethods(left_most)) |
| 522 return; | 309 return; |
| 523 if (left_most_base) { | 310 if (left_most_base) { |
| 524 // Get the base next to the "safe polymorphic base" | 311 // Get the base next to the "safe polymorphic base" |
| 525 if (it != left_most->bases_end()) | 312 if (it != left_most->bases_end()) |
| 526 ++it; | 313 ++it; |
| 527 if (it != left_most->bases_end()) { | 314 if (it != left_most->bases_end()) { |
| 528 if (CXXRecordDecl* next_base = it->getType()->getAsCXXRecordDecl()) { | 315 if (CXXRecordDecl* next_base = it->getType()->getAsCXXRecordDecl()) { |
| 529 if (CXXRecordDecl* next_left_most = GetLeftMostBase(next_base)) { | 316 if (CXXRecordDecl* next_left_most = GetLeftMostBase(next_base)) { |
| 530 if (DeclaresVirtualMethods(next_left_most)) | 317 if (DeclaresVirtualMethods(next_left_most)) |
| 531 return; | 318 return; |
| 532 ReportLeftMostBaseMustBePolymorphic(info, next_left_most); | 319 reporter_.LeftMostBaseMustBePolymorphic(info, next_left_most); |
| 533 return; | 320 return; |
| 534 } | 321 } |
| 535 } | 322 } |
| 536 } | 323 } |
| 537 } | 324 } |
| 538 ReportLeftMostBaseMustBePolymorphic(info, left_most); | 325 reporter_.LeftMostBaseMustBePolymorphic(info, left_most); |
| 539 } | 326 } |
| 540 } | 327 } |
| 541 | 328 |
| 542 CXXRecordDecl* BlinkGCPluginConsumer::GetLeftMostBase( | 329 CXXRecordDecl* BlinkGCPluginConsumer::GetLeftMostBase( |
| 543 CXXRecordDecl* left_most) { | 330 CXXRecordDecl* left_most) { |
| 544 CXXRecordDecl::base_class_iterator it = left_most->bases_begin(); | 331 CXXRecordDecl::base_class_iterator it = left_most->bases_begin(); |
| 545 while (it != left_most->bases_end()) { | 332 while (it != left_most->bases_end()) { |
| 546 if (it->getType()->isDependentType()) | 333 if (it->getType()->isDependentType()) |
| 547 left_most = RecordInfo::GetDependentTemplatedDecl(*it->getType()); | 334 left_most = RecordInfo::GetDependentTemplatedDecl(*it->getType()); |
| 548 else | 335 else |
| (...skipping 11 matching lines...) Expand all Loading... |
| 560 if (it->isVirtual() && !it->isPure()) | 347 if (it->isVirtual() && !it->isPure()) |
| 561 return true; | 348 return true; |
| 562 return false; | 349 return false; |
| 563 } | 350 } |
| 564 | 351 |
| 565 void BlinkGCPluginConsumer::CheckLeftMostDerived(RecordInfo* info) { | 352 void BlinkGCPluginConsumer::CheckLeftMostDerived(RecordInfo* info) { |
| 566 CXXRecordDecl* left_most = GetLeftMostBase(info->record()); | 353 CXXRecordDecl* left_most = GetLeftMostBase(info->record()); |
| 567 if (!left_most) | 354 if (!left_most) |
| 568 return; | 355 return; |
| 569 if (!Config::IsGCBase(left_most->getName())) | 356 if (!Config::IsGCBase(left_most->getName())) |
| 570 ReportClassMustLeftMostlyDeriveGC(info); | 357 reporter_.ClassMustLeftMostlyDeriveGC(info); |
| 571 } | 358 } |
| 572 | 359 |
| 573 void BlinkGCPluginConsumer::CheckDispatch(RecordInfo* info) { | 360 void BlinkGCPluginConsumer::CheckDispatch(RecordInfo* info) { |
| 574 bool finalized = info->IsGCFinalized(); | 361 bool finalized = info->IsGCFinalized(); |
| 575 CXXMethodDecl* trace_dispatch = info->GetTraceDispatchMethod(); | 362 CXXMethodDecl* trace_dispatch = info->GetTraceDispatchMethod(); |
| 576 CXXMethodDecl* finalize_dispatch = info->GetFinalizeDispatchMethod(); | 363 CXXMethodDecl* finalize_dispatch = info->GetFinalizeDispatchMethod(); |
| 577 if (!trace_dispatch && !finalize_dispatch) | 364 if (!trace_dispatch && !finalize_dispatch) |
| 578 return; | 365 return; |
| 579 | 366 |
| 580 CXXRecordDecl* base = trace_dispatch ? trace_dispatch->getParent() | 367 CXXRecordDecl* base = trace_dispatch ? trace_dispatch->getParent() |
| 581 : finalize_dispatch->getParent(); | 368 : finalize_dispatch->getParent(); |
| 582 | 369 |
| 583 // Check that dispatch methods are defined at the base. | 370 // Check that dispatch methods are defined at the base. |
| 584 if (base == info->record()) { | 371 if (base == info->record()) { |
| 585 if (!trace_dispatch) | 372 if (!trace_dispatch) |
| 586 ReportMissingTraceDispatchMethod(info); | 373 reporter_.MissingTraceDispatchMethod(info); |
| 587 if (finalized && !finalize_dispatch) | 374 if (finalized && !finalize_dispatch) |
| 588 ReportMissingFinalizeDispatchMethod(info); | 375 reporter_.MissingFinalizeDispatchMethod(info); |
| 589 if (!finalized && finalize_dispatch) { | 376 if (!finalized && finalize_dispatch) { |
| 590 ReportClassRequiresFinalization(info); | 377 reporter_.ClassRequiresFinalization(info); |
| 591 NoteUserDeclaredFinalizer(finalize_dispatch); | 378 reporter_.NoteUserDeclaredFinalizer(finalize_dispatch); |
| 592 } | 379 } |
| 593 } | 380 } |
| 594 | 381 |
| 595 // Check that classes implementing manual dispatch do not have vtables. | 382 // Check that classes implementing manual dispatch do not have vtables. |
| 596 if (info->record()->isPolymorphic()) { | 383 if (info->record()->isPolymorphic()) { |
| 597 ReportVirtualAndManualDispatch( | 384 reporter_.VirtualAndManualDispatch( |
| 598 info, trace_dispatch ? trace_dispatch : finalize_dispatch); | 385 info, trace_dispatch ? trace_dispatch : finalize_dispatch); |
| 599 } | 386 } |
| 600 | 387 |
| 601 // If this is a non-abstract class check that it is dispatched to. | 388 // If this is a non-abstract class check that it is dispatched to. |
| 602 // TODO: Create a global variant of this local check. We can only check if | 389 // TODO: Create a global variant of this local check. We can only check if |
| 603 // the dispatch body is known in this compilation unit. | 390 // the dispatch body is known in this compilation unit. |
| 604 if (info->IsConsideredAbstract()) | 391 if (info->IsConsideredAbstract()) |
| 605 return; | 392 return; |
| 606 | 393 |
| 607 const FunctionDecl* defn; | 394 const FunctionDecl* defn; |
| 608 | 395 |
| 609 if (trace_dispatch && trace_dispatch->isDefined(defn)) { | 396 if (trace_dispatch && trace_dispatch->isDefined(defn)) { |
| 610 CheckDispatchVisitor visitor(info); | 397 CheckDispatchVisitor visitor(info); |
| 611 visitor.TraverseStmt(defn->getBody()); | 398 visitor.TraverseStmt(defn->getBody()); |
| 612 if (!visitor.dispatched_to_receiver()) | 399 if (!visitor.dispatched_to_receiver()) |
| 613 ReportMissingTraceDispatch(defn, info); | 400 reporter_.MissingTraceDispatch(defn, info); |
| 614 } | 401 } |
| 615 | 402 |
| 616 if (finalized && finalize_dispatch && finalize_dispatch->isDefined(defn)) { | 403 if (finalized && finalize_dispatch && finalize_dispatch->isDefined(defn)) { |
| 617 CheckDispatchVisitor visitor(info); | 404 CheckDispatchVisitor visitor(info); |
| 618 visitor.TraverseStmt(defn->getBody()); | 405 visitor.TraverseStmt(defn->getBody()); |
| 619 if (!visitor.dispatched_to_receiver()) | 406 if (!visitor.dispatched_to_receiver()) |
| 620 ReportMissingFinalizeDispatch(defn, info); | 407 reporter_.MissingFinalizeDispatch(defn, info); |
| 621 } | 408 } |
| 622 } | 409 } |
| 623 | 410 |
| 624 // TODO: Should we collect destructors similar to trace methods? | 411 // TODO: Should we collect destructors similar to trace methods? |
| 625 void BlinkGCPluginConsumer::CheckFinalization(RecordInfo* info) { | 412 void BlinkGCPluginConsumer::CheckFinalization(RecordInfo* info) { |
| 626 CXXDestructorDecl* dtor = info->record()->getDestructor(); | 413 CXXDestructorDecl* dtor = info->record()->getDestructor(); |
| 627 | 414 |
| 628 // For finalized classes, check the finalization method if possible. | 415 // For finalized classes, check the finalization method if possible. |
| 629 if (info->IsGCFinalized()) { | 416 if (info->IsGCFinalized()) { |
| 630 if (dtor && dtor->hasBody()) { | 417 if (dtor && dtor->hasBody()) { |
| 631 CheckFinalizerVisitor visitor(&cache_, info->IsEagerlyFinalized()); | 418 CheckFinalizerVisitor visitor(&cache_, info->IsEagerlyFinalized()); |
| 632 visitor.TraverseCXXMethodDecl(dtor); | 419 visitor.TraverseCXXMethodDecl(dtor); |
| 633 if (!visitor.finalized_fields().empty()) { | 420 if (!visitor.finalized_fields().empty()) { |
| 634 ReportFinalizerAccessesFinalizedFields( | 421 reporter_.FinalizerAccessesFinalizedFields( |
| 635 dtor, visitor.finalized_fields()); | 422 dtor, visitor.finalized_fields()); |
| 636 } | 423 } |
| 637 } | 424 } |
| 638 return; | 425 return; |
| 639 } | 426 } |
| 640 | 427 |
| 641 // Don't require finalization of a mixin that has not yet been "mixed in". | 428 // Don't require finalization of a mixin that has not yet been "mixed in". |
| 642 if (info->IsGCMixin()) | 429 if (info->IsGCMixin()) |
| 643 return; | 430 return; |
| 644 | 431 |
| 645 // Report the finalization error, and proceed to print possible causes for | 432 // Report the finalization error, and proceed to print possible causes for |
| 646 // the finalization requirement. | 433 // the finalization requirement. |
| 647 ReportClassRequiresFinalization(info); | 434 reporter_.ClassRequiresFinalization(info); |
| 648 | 435 |
| 649 if (dtor && dtor->isUserProvided()) | 436 if (dtor && dtor->isUserProvided()) |
| 650 NoteUserDeclaredDestructor(dtor); | 437 reporter_.NoteUserDeclaredDestructor(dtor); |
| 651 | 438 |
| 652 for (auto& base : info->GetBases()) | 439 for (auto& base : info->GetBases()) |
| 653 if (base.second.info()->NeedsFinalization()) | 440 if (base.second.info()->NeedsFinalization()) |
| 654 NoteBaseRequiresFinalization(&base.second); | 441 reporter_.NoteBaseRequiresFinalization(&base.second); |
| 655 | 442 |
| 656 for (auto& field : info->GetFields()) | 443 for (auto& field : info->GetFields()) |
| 657 if (field.second.edge()->NeedsFinalization()) | 444 if (field.second.edge()->NeedsFinalization()) |
| 658 NoteField(&field.second, diag_field_requires_finalization_note_); | 445 reporter_.NoteFieldRequiresFinalization(&field.second); |
| 659 } | 446 } |
| 660 | 447 |
| 661 void BlinkGCPluginConsumer::CheckUnneededFinalization(RecordInfo* info) { | 448 void BlinkGCPluginConsumer::CheckUnneededFinalization(RecordInfo* info) { |
| 662 if (!HasNonEmptyFinalizer(info)) | 449 if (!HasNonEmptyFinalizer(info)) |
| 663 ReportClassDoesNotRequireFinalization(info); | 450 reporter_.ClassDoesNotRequireFinalization(info); |
| 664 } | 451 } |
| 665 | 452 |
| 666 bool BlinkGCPluginConsumer::HasNonEmptyFinalizer(RecordInfo* info) { | 453 bool BlinkGCPluginConsumer::HasNonEmptyFinalizer(RecordInfo* info) { |
| 667 CXXDestructorDecl* dtor = info->record()->getDestructor(); | 454 CXXDestructorDecl* dtor = info->record()->getDestructor(); |
| 668 | 455 |
| 669 // If the destructor is virtual (or one of the bases are by way of the | 456 // If the destructor is virtual (or one of the bases are by way of the |
| 670 // recursive call below), consider this class as having a non-empty | 457 // recursive call below), consider this class as having a non-empty |
| 671 // finalizer. Not doing so runs counter to standard C++ reflexes like | 458 // finalizer. Not doing so runs counter to standard C++ reflexes like |
| 672 // | 459 // |
| 673 // class A : public GarbageCollectedMixin { | 460 // class A : public GarbageCollectedMixin { |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 741 } | 528 } |
| 742 | 529 |
| 743 void BlinkGCPluginConsumer::CheckTraceMethod( | 530 void BlinkGCPluginConsumer::CheckTraceMethod( |
| 744 RecordInfo* parent, | 531 RecordInfo* parent, |
| 745 CXXMethodDecl* trace, | 532 CXXMethodDecl* trace, |
| 746 Config::TraceMethodType trace_type) { | 533 Config::TraceMethodType trace_type) { |
| 747 // A trace method must not override any non-virtual trace methods. | 534 // A trace method must not override any non-virtual trace methods. |
| 748 if (trace_type == Config::TRACE_METHOD) { | 535 if (trace_type == Config::TRACE_METHOD) { |
| 749 for (auto& base : parent->GetBases()) | 536 for (auto& base : parent->GetBases()) |
| 750 if (CXXMethodDecl* other = base.second.info()->InheritsNonVirtualTrace()) | 537 if (CXXMethodDecl* other = base.second.info()->InheritsNonVirtualTrace()) |
| 751 ReportOverriddenNonVirtualTrace(parent, trace, other); | 538 reporter_.OverriddenNonVirtualTrace(parent, trace, other); |
| 752 } | 539 } |
| 753 | 540 |
| 754 CheckTraceVisitor visitor(trace, parent, &cache_); | 541 CheckTraceVisitor visitor(trace, parent, &cache_); |
| 755 visitor.TraverseCXXMethodDecl(trace); | 542 visitor.TraverseCXXMethodDecl(trace); |
| 756 | 543 |
| 757 // Skip reporting if this trace method is a just delegate to | 544 // Skip reporting if this trace method is a just delegate to |
| 758 // traceImpl (or traceAfterDispatchImpl) method. We will report on | 545 // traceImpl (or traceAfterDispatchImpl) method. We will report on |
| 759 // CheckTraceMethod on traceImpl method. | 546 // CheckTraceMethod on traceImpl method. |
| 760 if (visitor.delegates_to_traceimpl()) | 547 if (visitor.delegates_to_traceimpl()) |
| 761 return; | 548 return; |
| 762 | 549 |
| 763 for (auto& base : parent->GetBases()) | 550 for (auto& base : parent->GetBases()) |
| 764 if (!base.second.IsProperlyTraced()) | 551 if (!base.second.IsProperlyTraced()) |
| 765 ReportBaseRequiresTracing(parent, trace, base.first); | 552 reporter_.BaseRequiresTracing(parent, trace, base.first); |
| 766 | 553 |
| 767 for (auto& field : parent->GetFields()) { | 554 for (auto& field : parent->GetFields()) { |
| 768 if (!field.second.IsProperlyTraced()) { | 555 if (!field.second.IsProperlyTraced()) { |
| 769 // Discontinue once an untraced-field error is found. | 556 // Discontinue once an untraced-field error is found. |
| 770 ReportFieldsRequireTracing(parent, trace); | 557 reporter_.FieldsRequireTracing(parent, trace); |
| 771 break; | 558 break; |
| 772 } | 559 } |
| 773 } | 560 } |
| 774 } | 561 } |
| 775 | 562 |
| 776 void BlinkGCPluginConsumer::DumpClass(RecordInfo* info) { | 563 void BlinkGCPluginConsumer::DumpClass(RecordInfo* info) { |
| 777 if (!json_) | 564 if (!json_) |
| 778 return; | 565 return; |
| 779 | 566 |
| 780 json_->OpenObject(); | 567 json_->OpenObject(); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 851 "<super>", | 638 "<super>", |
| 852 Edge::kStrong, | 639 Edge::kStrong, |
| 853 GetLocString(base.second.spec().getLocStart())); | 640 GetLocString(base.second.spec().getLocStart())); |
| 854 | 641 |
| 855 for (auto& field : info->GetFields()) | 642 for (auto& field : info->GetFields()) |
| 856 visitor.DumpField(info, | 643 visitor.DumpField(info, |
| 857 &field.second, | 644 &field.second, |
| 858 GetLocString(field.second.field()->getLocStart())); | 645 GetLocString(field.second.field()->getLocStart())); |
| 859 } | 646 } |
| 860 | 647 |
| 861 DiagnosticsEngine::Level BlinkGCPluginConsumer::getErrorLevel() { | |
| 862 return diagnostic_.getWarningsAsErrors() ? DiagnosticsEngine::Error | |
| 863 : DiagnosticsEngine::Warning; | |
| 864 } | |
| 865 | |
| 866 std::string BlinkGCPluginConsumer::GetLocString(SourceLocation loc) { | 648 std::string BlinkGCPluginConsumer::GetLocString(SourceLocation loc) { |
| 867 const SourceManager& source_manager = instance_.getSourceManager(); | 649 const SourceManager& source_manager = instance_.getSourceManager(); |
| 868 PresumedLoc ploc = source_manager.getPresumedLoc(loc); | 650 PresumedLoc ploc = source_manager.getPresumedLoc(loc); |
| 869 if (ploc.isInvalid()) | 651 if (ploc.isInvalid()) |
| 870 return ""; | 652 return ""; |
| 871 std::string loc_str; | 653 std::string loc_str; |
| 872 llvm::raw_string_ostream os(loc_str); | 654 llvm::raw_string_ostream os(loc_str); |
| 873 os << ploc.getFilename() | 655 os << ploc.getFilename() |
| 874 << ":" << ploc.getLine() | 656 << ":" << ploc.getLine() |
| 875 << ":" << ploc.getColumn(); | 657 << ":" << ploc.getColumn(); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 930 SourceLocation spelling_location = source_manager.getSpellingLoc(loc); | 712 SourceLocation spelling_location = source_manager.getSpellingLoc(loc); |
| 931 PresumedLoc ploc = source_manager.getPresumedLoc(spelling_location); | 713 PresumedLoc ploc = source_manager.getPresumedLoc(spelling_location); |
| 932 if (ploc.isInvalid()) { | 714 if (ploc.isInvalid()) { |
| 933 // If we're in an invalid location, we're looking at things that aren't | 715 // If we're in an invalid location, we're looking at things that aren't |
| 934 // actually stated in the source. | 716 // actually stated in the source. |
| 935 return false; | 717 return false; |
| 936 } | 718 } |
| 937 *filename = ploc.getFilename(); | 719 *filename = ploc.getFilename(); |
| 938 return true; | 720 return true; |
| 939 } | 721 } |
| 940 | |
| 941 DiagnosticBuilder BlinkGCPluginConsumer::ReportDiagnostic( | |
| 942 SourceLocation location, | |
| 943 unsigned diag_id) { | |
| 944 SourceManager& manager = instance_.getSourceManager(); | |
| 945 FullSourceLoc full_loc(location, manager); | |
| 946 return diagnostic_.Report(full_loc, diag_id); | |
| 947 } | |
| 948 | |
| 949 void BlinkGCPluginConsumer::ReportClassMustLeftMostlyDeriveGC( | |
| 950 RecordInfo* info) { | |
| 951 ReportDiagnostic(info->record()->getInnerLocStart(), | |
| 952 diag_class_must_left_mostly_derive_gc_) | |
| 953 << info->record(); | |
| 954 } | |
| 955 | |
| 956 void BlinkGCPluginConsumer::ReportClassRequiresTraceMethod(RecordInfo* info) { | |
| 957 ReportDiagnostic(info->record()->getInnerLocStart(), | |
| 958 diag_class_requires_trace_method_) | |
| 959 << info->record(); | |
| 960 | |
| 961 for (auto& base : info->GetBases()) | |
| 962 if (base.second.NeedsTracing().IsNeeded()) | |
| 963 NoteBaseRequiresTracing(&base.second); | |
| 964 | |
| 965 for (auto& field : info->GetFields()) | |
| 966 if (!field.second.IsProperlyTraced()) | |
| 967 NoteFieldRequiresTracing(info, field.first); | |
| 968 } | |
| 969 | |
| 970 void BlinkGCPluginConsumer::ReportBaseRequiresTracing( | |
| 971 RecordInfo* derived, | |
| 972 CXXMethodDecl* trace, | |
| 973 CXXRecordDecl* base) { | |
| 974 ReportDiagnostic(trace->getLocStart(), diag_base_requires_tracing_) | |
| 975 << base << derived->record(); | |
| 976 } | |
| 977 | |
| 978 void BlinkGCPluginConsumer::ReportFieldsRequireTracing( | |
| 979 RecordInfo* info, | |
| 980 CXXMethodDecl* trace) { | |
| 981 ReportDiagnostic(trace->getLocStart(), diag_fields_require_tracing_) | |
| 982 << info->record(); | |
| 983 for (auto& field : info->GetFields()) | |
| 984 if (!field.second.IsProperlyTraced()) | |
| 985 NoteFieldRequiresTracing(info, field.first); | |
| 986 } | |
| 987 | |
| 988 void BlinkGCPluginConsumer::ReportClassContainsInvalidFields( | |
| 989 RecordInfo* info, | |
| 990 const CheckFieldsVisitor::Errors& errors) { | |
| 991 | |
| 992 ReportDiagnostic(info->record()->getLocStart(), | |
| 993 diag_class_contains_invalid_fields_) | |
| 994 << info->record(); | |
| 995 | |
| 996 for (auto& error : errors) { | |
| 997 unsigned note; | |
| 998 if (error.second == CheckFieldsVisitor::kRawPtrToGCManaged) { | |
| 999 note = diag_raw_ptr_to_gc_managed_class_note_; | |
| 1000 } else if (error.second == CheckFieldsVisitor::kRefPtrToGCManaged) { | |
| 1001 note = diag_ref_ptr_to_gc_managed_class_note_; | |
| 1002 } else if (error.second == CheckFieldsVisitor::kReferencePtrToGCManaged) { | |
| 1003 note = diag_reference_ptr_to_gc_managed_class_note_; | |
| 1004 } else if (error.second == CheckFieldsVisitor::kOwnPtrToGCManaged) { | |
| 1005 note = diag_own_ptr_to_gc_managed_class_note_; | |
| 1006 } else if (error.second == CheckFieldsVisitor::kMemberToGCUnmanaged) { | |
| 1007 note = diag_member_to_gc_unmanaged_class_note_; | |
| 1008 } else if (error.second == CheckFieldsVisitor::kMemberInUnmanaged) { | |
| 1009 note = diag_member_in_unmanaged_class_note_; | |
| 1010 } else if (error.second == CheckFieldsVisitor::kPtrFromHeapToStack) { | |
| 1011 note = diag_stack_allocated_field_note_; | |
| 1012 } else if (error.second == CheckFieldsVisitor::kGCDerivedPartObject) { | |
| 1013 note = diag_part_object_to_gc_derived_class_note_; | |
| 1014 } else { | |
| 1015 assert(false && "Unknown field error"); | |
| 1016 } | |
| 1017 NoteField(error.first, note); | |
| 1018 } | |
| 1019 } | |
| 1020 | |
| 1021 void BlinkGCPluginConsumer::ReportClassContainsGCRoots( | |
| 1022 RecordInfo* info, | |
| 1023 const CheckGCRootsVisitor::Errors& errors) { | |
| 1024 for (auto& error : errors) { | |
| 1025 FieldPoint* point = nullptr; | |
| 1026 for (FieldPoint* path : error) { | |
| 1027 if (!point) { | |
| 1028 point = path; | |
| 1029 ReportDiagnostic(info->record()->getLocStart(), | |
| 1030 diag_class_contains_gc_root_) | |
| 1031 << info->record() << point->field(); | |
| 1032 continue; | |
| 1033 } | |
| 1034 NotePartObjectContainsGCRoot(point); | |
| 1035 point = path; | |
| 1036 } | |
| 1037 NoteFieldContainsGCRoot(point); | |
| 1038 } | |
| 1039 } | |
| 1040 | |
| 1041 void BlinkGCPluginConsumer::ReportFinalizerAccessesFinalizedFields( | |
| 1042 CXXMethodDecl* dtor, | |
| 1043 const CheckFinalizerVisitor::Errors& errors) { | |
| 1044 for (auto& error : errors) { | |
| 1045 bool as_eagerly_finalized = error.as_eagerly_finalized; | |
| 1046 unsigned diag_error = as_eagerly_finalized ? | |
| 1047 diag_finalizer_eagerly_finalized_field_ : | |
| 1048 diag_finalizer_accesses_finalized_field_; | |
| 1049 unsigned diag_note = as_eagerly_finalized ? | |
| 1050 diag_eagerly_finalized_field_note_ : | |
| 1051 diag_finalized_field_note_; | |
| 1052 ReportDiagnostic(error.member->getLocStart(), diag_error) | |
| 1053 << dtor << error.field->field(); | |
| 1054 NoteField(error.field, diag_note); | |
| 1055 } | |
| 1056 } | |
| 1057 | |
| 1058 void BlinkGCPluginConsumer::ReportClassRequiresFinalization(RecordInfo* info) { | |
| 1059 ReportDiagnostic(info->record()->getInnerLocStart(), | |
| 1060 diag_class_requires_finalization_) | |
| 1061 << info->record(); | |
| 1062 } | |
| 1063 | |
| 1064 void BlinkGCPluginConsumer::ReportClassDoesNotRequireFinalization( | |
| 1065 RecordInfo* info) { | |
| 1066 ReportDiagnostic(info->record()->getInnerLocStart(), | |
| 1067 diag_class_does_not_require_finalization_) | |
| 1068 << info->record(); | |
| 1069 } | |
| 1070 | |
| 1071 void BlinkGCPluginConsumer::ReportOverriddenNonVirtualTrace( | |
| 1072 RecordInfo* info, | |
| 1073 CXXMethodDecl* trace, | |
| 1074 CXXMethodDecl* overridden) { | |
| 1075 ReportDiagnostic(trace->getLocStart(), diag_overridden_non_virtual_trace_) | |
| 1076 << info->record() << overridden->getParent(); | |
| 1077 NoteOverriddenNonVirtualTrace(overridden); | |
| 1078 } | |
| 1079 | |
| 1080 void BlinkGCPluginConsumer::ReportMissingTraceDispatchMethod(RecordInfo* info) { | |
| 1081 ReportMissingDispatchMethod(info, diag_missing_trace_dispatch_method_); | |
| 1082 } | |
| 1083 | |
| 1084 void BlinkGCPluginConsumer::ReportMissingFinalizeDispatchMethod( | |
| 1085 RecordInfo* info) { | |
| 1086 ReportMissingDispatchMethod(info, diag_missing_finalize_dispatch_method_); | |
| 1087 } | |
| 1088 | |
| 1089 void BlinkGCPluginConsumer::ReportMissingDispatchMethod( | |
| 1090 RecordInfo* info, | |
| 1091 unsigned error) { | |
| 1092 ReportDiagnostic(info->record()->getInnerLocStart(), error) | |
| 1093 << info->record(); | |
| 1094 } | |
| 1095 | |
| 1096 void BlinkGCPluginConsumer::ReportVirtualAndManualDispatch( | |
| 1097 RecordInfo* info, | |
| 1098 CXXMethodDecl* dispatch) { | |
| 1099 ReportDiagnostic(info->record()->getInnerLocStart(), | |
| 1100 diag_virtual_and_manual_dispatch_) | |
| 1101 << info->record(); | |
| 1102 NoteManualDispatchMethod(dispatch); | |
| 1103 } | |
| 1104 | |
| 1105 void BlinkGCPluginConsumer::ReportMissingTraceDispatch( | |
| 1106 const FunctionDecl* dispatch, | |
| 1107 RecordInfo* receiver) { | |
| 1108 ReportMissingDispatch(dispatch, receiver, diag_missing_trace_dispatch_); | |
| 1109 } | |
| 1110 | |
| 1111 void BlinkGCPluginConsumer::ReportMissingFinalizeDispatch( | |
| 1112 const FunctionDecl* dispatch, | |
| 1113 RecordInfo* receiver) { | |
| 1114 ReportMissingDispatch(dispatch, receiver, diag_missing_finalize_dispatch_); | |
| 1115 } | |
| 1116 | |
| 1117 void BlinkGCPluginConsumer::ReportMissingDispatch( | |
| 1118 const FunctionDecl* dispatch, | |
| 1119 RecordInfo* receiver, | |
| 1120 unsigned error) { | |
| 1121 ReportDiagnostic(dispatch->getLocStart(), error) << receiver->record(); | |
| 1122 } | |
| 1123 | |
| 1124 void BlinkGCPluginConsumer::ReportDerivesNonStackAllocated( | |
| 1125 RecordInfo* info, | |
| 1126 BasePoint* base) { | |
| 1127 ReportDiagnostic(base->spec().getLocStart(), | |
| 1128 diag_derives_non_stack_allocated_) | |
| 1129 << info->record() << base->info()->record(); | |
| 1130 } | |
| 1131 | |
| 1132 void BlinkGCPluginConsumer::ReportClassOverridesNew( | |
| 1133 RecordInfo* info, | |
| 1134 CXXMethodDecl* newop) { | |
| 1135 ReportDiagnostic(newop->getLocStart(), diag_class_overrides_new_) | |
| 1136 << info->record(); | |
| 1137 } | |
| 1138 | |
| 1139 void BlinkGCPluginConsumer::ReportClassDeclaresPureVirtualTrace( | |
| 1140 RecordInfo* info, | |
| 1141 CXXMethodDecl* trace) { | |
| 1142 ReportDiagnostic(trace->getLocStart(), | |
| 1143 diag_class_declares_pure_virtual_trace_) | |
| 1144 << info->record(); | |
| 1145 } | |
| 1146 | |
| 1147 void BlinkGCPluginConsumer::ReportLeftMostBaseMustBePolymorphic( | |
| 1148 RecordInfo* derived, | |
| 1149 CXXRecordDecl* base) { | |
| 1150 ReportDiagnostic(base->getLocStart(), | |
| 1151 diag_left_most_base_must_be_polymorphic_) | |
| 1152 << base << derived->record(); | |
| 1153 } | |
| 1154 | |
| 1155 void BlinkGCPluginConsumer::ReportBaseClassMustDeclareVirtualTrace( | |
| 1156 RecordInfo* derived, | |
| 1157 CXXRecordDecl* base) { | |
| 1158 ReportDiagnostic(base->getLocStart(), | |
| 1159 diag_base_class_must_declare_virtual_trace_) | |
| 1160 << base << derived->record(); | |
| 1161 } | |
| 1162 | |
| 1163 void BlinkGCPluginConsumer::NoteManualDispatchMethod(CXXMethodDecl* dispatch) { | |
| 1164 ReportDiagnostic(dispatch->getLocStart(), | |
| 1165 diag_manual_dispatch_method_note_) | |
| 1166 << dispatch; | |
| 1167 } | |
| 1168 | |
| 1169 void BlinkGCPluginConsumer::NoteBaseRequiresTracing(BasePoint* base) { | |
| 1170 ReportDiagnostic(base->spec().getLocStart(), | |
| 1171 diag_base_requires_tracing_note_) | |
| 1172 << base->info()->record(); | |
| 1173 } | |
| 1174 | |
| 1175 void BlinkGCPluginConsumer::NoteFieldRequiresTracing( | |
| 1176 RecordInfo* holder, | |
| 1177 FieldDecl* field) { | |
| 1178 NoteField(field, diag_field_requires_tracing_note_); | |
| 1179 } | |
| 1180 | |
| 1181 void BlinkGCPluginConsumer::NotePartObjectContainsGCRoot(FieldPoint* point) { | |
| 1182 FieldDecl* field = point->field(); | |
| 1183 ReportDiagnostic(field->getLocStart(), | |
| 1184 diag_part_object_contains_gc_root_note_) | |
| 1185 << field << field->getParent(); | |
| 1186 } | |
| 1187 | |
| 1188 void BlinkGCPluginConsumer::NoteFieldContainsGCRoot(FieldPoint* point) { | |
| 1189 NoteField(point, diag_field_contains_gc_root_note_); | |
| 1190 } | |
| 1191 | |
| 1192 void BlinkGCPluginConsumer::NoteUserDeclaredDestructor(CXXMethodDecl* dtor) { | |
| 1193 ReportDiagnostic(dtor->getLocStart(), diag_user_declared_destructor_note_); | |
| 1194 } | |
| 1195 | |
| 1196 void BlinkGCPluginConsumer::NoteUserDeclaredFinalizer(CXXMethodDecl* dtor) { | |
| 1197 ReportDiagnostic(dtor->getLocStart(), diag_user_declared_finalizer_note_); | |
| 1198 } | |
| 1199 | |
| 1200 void BlinkGCPluginConsumer::NoteBaseRequiresFinalization(BasePoint* base) { | |
| 1201 ReportDiagnostic(base->spec().getLocStart(), | |
| 1202 diag_base_requires_finalization_note_) | |
| 1203 << base->info()->record(); | |
| 1204 } | |
| 1205 | |
| 1206 void BlinkGCPluginConsumer::NoteField(FieldPoint* point, unsigned note) { | |
| 1207 NoteField(point->field(), note); | |
| 1208 } | |
| 1209 | |
| 1210 void BlinkGCPluginConsumer::NoteField(FieldDecl* field, unsigned note) { | |
| 1211 ReportDiagnostic(field->getLocStart(), note) << field; | |
| 1212 } | |
| 1213 | |
| 1214 void BlinkGCPluginConsumer::NoteOverriddenNonVirtualTrace( | |
| 1215 CXXMethodDecl* overridden) { | |
| 1216 ReportDiagnostic(overridden->getLocStart(), | |
| 1217 diag_overridden_non_virtual_trace_note_) | |
| 1218 << overridden; | |
| 1219 } | |
| OLD | NEW |