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 |