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

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

Issue 206123004: Add checks for stack-allocated types and their uses in fields. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tools/clang/blink_gc_plugin/RecordInfo.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 // This clang plugin checks various invariants of the Blink garbage 5 // This clang plugin checks various invariants of the Blink garbage
6 // collection infrastructure. 6 // collection infrastructure.
7 // 7 //
8 // Errors are described at: 8 // Errors are described at:
9 // http://www.chromium.org/developers/blink-gc-plugin-errors 9 // http://www.chromium.org/developers/blink-gc-plugin-errors
10 10
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 49
50 const char kRawPtrToGCManagedClassNote[] = 50 const char kRawPtrToGCManagedClassNote[] =
51 "[blink-gc] Raw pointer field %0 to a GC managed class declared here:"; 51 "[blink-gc] Raw pointer field %0 to a GC managed class declared here:";
52 52
53 const char kRefPtrToGCManagedClassNote[] = 53 const char kRefPtrToGCManagedClassNote[] =
54 "[blink-gc] RefPtr field %0 to a GC managed class declared here:"; 54 "[blink-gc] RefPtr field %0 to a GC managed class declared here:";
55 55
56 const char kOwnPtrToGCManagedClassNote[] = 56 const char kOwnPtrToGCManagedClassNote[] =
57 "[blink-gc] OwnPtr field %0 to a GC managed class declared here:"; 57 "[blink-gc] OwnPtr field %0 to a GC managed class declared here:";
58 58
59 const char kStackAllocatedFieldNote[] =
60 "[blink-gc] Stack-allocated field %0 declared here:";
61
59 const char kPartObjectContainsGCRoot[] = 62 const char kPartObjectContainsGCRoot[] =
60 "[blink-gc] Field %0 with embedded GC root in %1 declared here:"; 63 "[blink-gc] Field %0 with embedded GC root in %1 declared here:";
61 64
62 const char kFieldContainsGCRoot[] = 65 const char kFieldContainsGCRoot[] =
63 "[blink-gc] Field %0 defining a GC root declared here:"; 66 "[blink-gc] Field %0 defining a GC root declared here:";
64 67
65 const char kOverriddenNonVirtualTrace[] = 68 const char kOverriddenNonVirtualTrace[] =
66 "[blink-gc] Class %0 overrides non-virtual trace of base class %1."; 69 "[blink-gc] Class %0 overrides non-virtual trace of base class %1.";
67 70
68 const char kOverriddenNonVirtualTraceNote[] = 71 const char kOverriddenNonVirtualTraceNote[] =
(...skipping 26 matching lines...) Expand all
95 98
96 const char kBaseRequiresFinalizationNote[] = 99 const char kBaseRequiresFinalizationNote[] =
97 "[blink-gc] Base class %0 requiring finalization declared here:"; 100 "[blink-gc] Base class %0 requiring finalization declared here:";
98 101
99 const char kFieldRequiresFinalizationNote[] = 102 const char kFieldRequiresFinalizationNote[] =
100 "[blink-gc] Field %0 requiring finalization declared here:"; 103 "[blink-gc] Field %0 requiring finalization declared here:";
101 104
102 const char kManualDispatchMethodNote[] = 105 const char kManualDispatchMethodNote[] =
103 "[blink-gc] Manual dispatch %0 declared here:"; 106 "[blink-gc] Manual dispatch %0 declared here:";
104 107
108 const char kDerivesNonStackAllocated[] =
109 "[blink-gc] Stack-allocated class %0 derives class %1"
110 " which is not stack allocated.";
111
105 struct BlinkGCPluginOptions { 112 struct BlinkGCPluginOptions {
106 BlinkGCPluginOptions() : enable_oilpan(false) {} 113 BlinkGCPluginOptions() : enable_oilpan(false) {}
107 bool enable_oilpan; 114 bool enable_oilpan;
108 std::set<std::string> ignored_classes; 115 std::set<std::string> ignored_classes;
109 std::set<std::string> checked_namespaces; 116 std::set<std::string> checked_namespaces;
110 std::vector<std::string> ignored_directories; 117 std::vector<std::string> ignored_directories;
111 }; 118 };
112 119
113 typedef std::vector<CXXRecordDecl*> RecordVector; 120 typedef std::vector<CXXRecordDecl*> RecordVector;
114 typedef std::vector<CXXMethodDecl*> MethodVector; 121 typedef std::vector<CXXMethodDecl*> MethodVector;
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 }; 424 };
418 425
419 // This visitor checks that the fields of a class are "well formed". 426 // This visitor checks that the fields of a class are "well formed".
420 // - OwnPtr, RefPtr and RawPtr must not point to a GC derived types. 427 // - OwnPtr, RefPtr and RawPtr must not point to a GC derived types.
421 // - An on-heap class must never contain GC roots. 428 // - An on-heap class must never contain GC roots.
422 class CheckFieldsVisitor : public RecursiveEdgeVisitor { 429 class CheckFieldsVisitor : public RecursiveEdgeVisitor {
423 public: 430 public:
424 typedef std::vector<std::pair<FieldPoint*, Edge*> > Errors; 431 typedef std::vector<std::pair<FieldPoint*, Edge*> > Errors;
425 432
426 CheckFieldsVisitor(const BlinkGCPluginOptions& options) 433 CheckFieldsVisitor(const BlinkGCPluginOptions& options)
427 : options_(options), current_(0) {} 434 : options_(options), current_(0), stack_allocated_host_(false) {}
428 435
429 Errors& invalid_fields() { return invalid_fields_; } 436 Errors& invalid_fields() { return invalid_fields_; }
430 437
431 bool ContainsInvalidFields(RecordInfo* info) { 438 bool ContainsInvalidFields(RecordInfo* info) {
439 stack_allocated_host_ = info->IsStackAllocated();
432 for (RecordInfo::Fields::iterator it = info->GetFields().begin(); 440 for (RecordInfo::Fields::iterator it = info->GetFields().begin();
433 it != info->GetFields().end(); 441 it != info->GetFields().end();
434 ++it) { 442 ++it) {
435 context().clear(); 443 context().clear();
436 current_ = &it->second; 444 current_ = &it->second;
437 current_->edge()->Accept(this); 445 current_->edge()->Accept(this);
438 } 446 }
439 return !invalid_fields_.empty(); 447 return !invalid_fields_.empty();
440 } 448 }
441 449
442 void VisitValue(Value* edge) { 450 void VisitValue(Value* edge) {
443 // TODO: what should we do to check unions? 451 // TODO: what should we do to check unions?
444 if (edge->value()->record()->isUnion()) 452 if (edge->value()->record()->isUnion())
445 return; 453 return;
446 454
455 if (!stack_allocated_host_ && edge->value()->IsStackAllocated())
456 invalid_fields_.push_back(std::make_pair(current_, edge));
457
447 if (!Parent() || !edge->value()->IsGCAllocated()) 458 if (!Parent() || !edge->value()->IsGCAllocated())
448 return; 459 return;
449 460
450 if (Parent()->IsOwnPtr()) 461 if (Parent()->IsOwnPtr())
451 invalid_fields_.push_back(std::make_pair(current_, Parent())); 462 invalid_fields_.push_back(std::make_pair(current_, Parent()));
452 463
453 // Don't check raw and ref pointers in transition mode. 464 // Don't check raw and ref pointers in transition mode.
454 if (options_.enable_oilpan) 465 if (options_.enable_oilpan)
455 return; 466 return;
456 467
457 if (Parent()->IsRawPtr() || Parent()->IsRefPtr()) 468 if ((!stack_allocated_host_ && Parent()->IsRawPtr()) ||
469 Parent()->IsRefPtr())
458 invalid_fields_.push_back(std::make_pair(current_, Parent())); 470 invalid_fields_.push_back(std::make_pair(current_, Parent()));
459 } 471 }
460 472
461 private: 473 private:
462 const BlinkGCPluginOptions& options_; 474 const BlinkGCPluginOptions& options_;
463 FieldPoint* current_; 475 FieldPoint* current_;
476 bool stack_allocated_host_;
464 Errors invalid_fields_; 477 Errors invalid_fields_;
465 }; 478 };
466 479
467 // Main class containing checks for various invariants of the Blink 480 // Main class containing checks for various invariants of the Blink
468 // garbage collection infrastructure. 481 // garbage collection infrastructure.
469 class BlinkGCPluginConsumer : public ASTConsumer { 482 class BlinkGCPluginConsumer : public ASTConsumer {
470 public: 483 public:
471 BlinkGCPluginConsumer(CompilerInstance& instance, 484 BlinkGCPluginConsumer(CompilerInstance& instance,
472 const BlinkGCPluginOptions& options) 485 const BlinkGCPluginOptions& options)
473 : instance_(instance), 486 : instance_(instance),
(...skipping 29 matching lines...) Expand all
503 diag_missing_trace_dispatch_method_ = diagnostic_.getCustomDiagID( 516 diag_missing_trace_dispatch_method_ = diagnostic_.getCustomDiagID(
504 getErrorLevel(), kMissingTraceDispatchMethod); 517 getErrorLevel(), kMissingTraceDispatchMethod);
505 diag_missing_finalize_dispatch_method_ = diagnostic_.getCustomDiagID( 518 diag_missing_finalize_dispatch_method_ = diagnostic_.getCustomDiagID(
506 getErrorLevel(), kMissingFinalizeDispatchMethod); 519 getErrorLevel(), kMissingFinalizeDispatchMethod);
507 diag_virtual_and_manual_dispatch_ = diagnostic_.getCustomDiagID( 520 diag_virtual_and_manual_dispatch_ = diagnostic_.getCustomDiagID(
508 getErrorLevel(), kVirtualAndManualDispatch); 521 getErrorLevel(), kVirtualAndManualDispatch);
509 diag_missing_trace_dispatch_ = diagnostic_.getCustomDiagID( 522 diag_missing_trace_dispatch_ = diagnostic_.getCustomDiagID(
510 getErrorLevel(), kMissingTraceDispatch); 523 getErrorLevel(), kMissingTraceDispatch);
511 diag_missing_finalize_dispatch_ = diagnostic_.getCustomDiagID( 524 diag_missing_finalize_dispatch_ = diagnostic_.getCustomDiagID(
512 getErrorLevel(), kMissingFinalizeDispatch); 525 getErrorLevel(), kMissingFinalizeDispatch);
526 diag_derives_non_stack_allocated_ = diagnostic_.getCustomDiagID(
527 getErrorLevel(), kDerivesNonStackAllocated);
513 528
514 // Register note messages. 529 // Register note messages.
515 diag_field_requires_tracing_note_ = diagnostic_.getCustomDiagID( 530 diag_field_requires_tracing_note_ = diagnostic_.getCustomDiagID(
516 DiagnosticsEngine::Note, kFieldRequiresTracingNote); 531 DiagnosticsEngine::Note, kFieldRequiresTracingNote);
517 diag_raw_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( 532 diag_raw_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
518 DiagnosticsEngine::Note, kRawPtrToGCManagedClassNote); 533 DiagnosticsEngine::Note, kRawPtrToGCManagedClassNote);
519 diag_ref_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( 534 diag_ref_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
520 DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote); 535 DiagnosticsEngine::Note, kRefPtrToGCManagedClassNote);
521 diag_own_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID( 536 diag_own_ptr_to_gc_managed_class_note_ = diagnostic_.getCustomDiagID(
522 DiagnosticsEngine::Note, kOwnPtrToGCManagedClassNote); 537 DiagnosticsEngine::Note, kOwnPtrToGCManagedClassNote);
538 diag_stack_allocated_field_note_ = diagnostic_.getCustomDiagID(
539 DiagnosticsEngine::Note, kStackAllocatedFieldNote);
523 diag_part_object_contains_gc_root_note_ = diagnostic_.getCustomDiagID( 540 diag_part_object_contains_gc_root_note_ = diagnostic_.getCustomDiagID(
524 DiagnosticsEngine::Note, kPartObjectContainsGCRoot); 541 DiagnosticsEngine::Note, kPartObjectContainsGCRoot);
525 diag_field_contains_gc_root_note_ = diagnostic_.getCustomDiagID( 542 diag_field_contains_gc_root_note_ = diagnostic_.getCustomDiagID(
526 DiagnosticsEngine::Note, kFieldContainsGCRoot); 543 DiagnosticsEngine::Note, kFieldContainsGCRoot);
527 diag_finalized_field_note_ = diagnostic_.getCustomDiagID( 544 diag_finalized_field_note_ = diagnostic_.getCustomDiagID(
528 DiagnosticsEngine::Note, kFinalizedFieldNote); 545 DiagnosticsEngine::Note, kFinalizedFieldNote);
529 diag_user_declared_destructor_note_ = diagnostic_.getCustomDiagID( 546 diag_user_declared_destructor_note_ = diagnostic_.getCustomDiagID(
530 DiagnosticsEngine::Note, kUserDeclaredDestructorNote); 547 DiagnosticsEngine::Note, kUserDeclaredDestructorNote);
531 diag_user_declared_finalizer_note_ = diagnostic_.getCustomDiagID( 548 diag_user_declared_finalizer_note_ = diagnostic_.getCustomDiagID(
532 DiagnosticsEngine::Note, kUserDeclaredFinalizerNote); 549 DiagnosticsEngine::Note, kUserDeclaredFinalizerNote);
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
578 CheckClass(cache_.Lookup(*it)); 595 CheckClass(cache_.Lookup(*it));
579 } 596 }
580 return; 597 return;
581 } 598 }
582 599
583 CheckClass(info); 600 CheckClass(info);
584 } 601 }
585 602
586 // Check a class-like object (eg, class, specialization, instantiation). 603 // Check a class-like object (eg, class, specialization, instantiation).
587 void CheckClass(RecordInfo* info) { 604 void CheckClass(RecordInfo* info) {
588 // Don't enforce tracing of stack allocated objects. 605 if (!info)
589 if (!info || info->IsStackAllocated())
590 return; 606 return;
591 607
608 // Check consistency of stack-allocated hierarchies.
609 if (info->IsStackAllocated()) {
610 for (RecordInfo::Bases::iterator it = info->GetBases().begin();
611 it != info->GetBases().end();
612 ++it) {
613 if (!it->second.info()->IsStackAllocated())
614 ReportDerivesNonStackAllocated(info, &it->second);
615 }
616 }
617
592 if (info->RequiresTraceMethod() && !info->GetTraceMethod()) 618 if (info->RequiresTraceMethod() && !info->GetTraceMethod())
593 ReportClassRequiresTraceMethod(info); 619 ReportClassRequiresTraceMethod(info);
594 620
595 CheckDispatch(info); 621 CheckDispatch(info);
596 622
597 { 623 {
598 CheckFieldsVisitor visitor(options_); 624 CheckFieldsVisitor visitor(options_);
599 if (visitor.ContainsInvalidFields(info)) 625 if (visitor.ContainsInvalidFields(info))
600 ReportClassContainsInvalidFields(info, &visitor.invalid_fields()); 626 ReportClassContainsInvalidFields(info, &visitor.invalid_fields());
601 } 627 }
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after
887 << info->record(); 913 << info->record();
888 for (CheckFieldsVisitor::Errors::iterator it = errors->begin(); 914 for (CheckFieldsVisitor::Errors::iterator it = errors->begin();
889 it != errors->end(); 915 it != errors->end();
890 ++it) { 916 ++it) {
891 if (it->second->IsRawPtr()) { 917 if (it->second->IsRawPtr()) {
892 NoteField(it->first, diag_raw_ptr_to_gc_managed_class_note_); 918 NoteField(it->first, diag_raw_ptr_to_gc_managed_class_note_);
893 } else if (it->second->IsRefPtr()) { 919 } else if (it->second->IsRefPtr()) {
894 NoteField(it->first, diag_ref_ptr_to_gc_managed_class_note_); 920 NoteField(it->first, diag_ref_ptr_to_gc_managed_class_note_);
895 } else if (it->second->IsOwnPtr()) { 921 } else if (it->second->IsOwnPtr()) {
896 NoteField(it->first, diag_own_ptr_to_gc_managed_class_note_); 922 NoteField(it->first, diag_own_ptr_to_gc_managed_class_note_);
923 } else if (it->second->IsValue()) {
924 NoteField(it->first, diag_stack_allocated_field_note_);
897 } 925 }
898 } 926 }
899 } 927 }
900 928
901 void ReportClassContainsGCRoots(RecordInfo* info, 929 void ReportClassContainsGCRoots(RecordInfo* info,
902 CheckGCRootsVisitor::Errors* errors) { 930 CheckGCRootsVisitor::Errors* errors) {
903 SourceLocation loc = info->record()->getLocStart(); 931 SourceLocation loc = info->record()->getLocStart();
904 SourceManager& manager = instance_.getSourceManager(); 932 SourceManager& manager = instance_.getSourceManager();
905 FullSourceLoc full_loc(loc, manager); 933 FullSourceLoc full_loc(loc, manager);
906 for (CheckGCRootsVisitor::Errors::iterator it = errors->begin(); 934 for (CheckGCRootsVisitor::Errors::iterator it = errors->begin();
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
990 1018
991 void ReportMissingDispatch(const FunctionDecl* dispatch, 1019 void ReportMissingDispatch(const FunctionDecl* dispatch,
992 RecordInfo* receiver, 1020 RecordInfo* receiver,
993 unsigned error) { 1021 unsigned error) {
994 SourceLocation loc = dispatch->getLocStart(); 1022 SourceLocation loc = dispatch->getLocStart();
995 SourceManager& manager = instance_.getSourceManager(); 1023 SourceManager& manager = instance_.getSourceManager();
996 FullSourceLoc full_loc(loc, manager); 1024 FullSourceLoc full_loc(loc, manager);
997 diagnostic_.Report(full_loc, error) << receiver->record(); 1025 diagnostic_.Report(full_loc, error) << receiver->record();
998 } 1026 }
999 1027
1028 void ReportDerivesNonStackAllocated(RecordInfo* info, BasePoint* base) {
1029 SourceLocation loc = base->spec().getLocStart();
1030 SourceManager& manager = instance_.getSourceManager();
1031 FullSourceLoc full_loc(loc, manager);
1032 diagnostic_.Report(full_loc, diag_derives_non_stack_allocated_)
1033 << info->record() << base->info()->record();
1034 }
1035
1000 void NoteManualDispatchMethod(CXXMethodDecl* dispatch) { 1036 void NoteManualDispatchMethod(CXXMethodDecl* dispatch) {
1001 SourceLocation loc = dispatch->getLocStart(); 1037 SourceLocation loc = dispatch->getLocStart();
1002 SourceManager& manager = instance_.getSourceManager(); 1038 SourceManager& manager = instance_.getSourceManager();
1003 FullSourceLoc full_loc(loc, manager); 1039 FullSourceLoc full_loc(loc, manager);
1004 diagnostic_.Report(full_loc, diag_manual_dispatch_method_note_) << dispatch; 1040 diagnostic_.Report(full_loc, diag_manual_dispatch_method_note_) << dispatch;
1005 } 1041 }
1006 1042
1007 void NoteFieldRequiresTracing(RecordInfo* holder, FieldDecl* field) { 1043 void NoteFieldRequiresTracing(RecordInfo* holder, FieldDecl* field) {
1008 NoteField(field, diag_field_requires_tracing_note_); 1044 NoteField(field, diag_field_requires_tracing_note_);
1009 } 1045 }
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
1068 unsigned diag_class_contains_invalid_fields_; 1104 unsigned diag_class_contains_invalid_fields_;
1069 unsigned diag_class_contains_gc_root_; 1105 unsigned diag_class_contains_gc_root_;
1070 unsigned diag_class_requires_finalization_; 1106 unsigned diag_class_requires_finalization_;
1071 unsigned diag_finalizer_accesses_finalized_field_; 1107 unsigned diag_finalizer_accesses_finalized_field_;
1072 unsigned diag_overridden_non_virtual_trace_; 1108 unsigned diag_overridden_non_virtual_trace_;
1073 unsigned diag_missing_trace_dispatch_method_; 1109 unsigned diag_missing_trace_dispatch_method_;
1074 unsigned diag_missing_finalize_dispatch_method_; 1110 unsigned diag_missing_finalize_dispatch_method_;
1075 unsigned diag_virtual_and_manual_dispatch_; 1111 unsigned diag_virtual_and_manual_dispatch_;
1076 unsigned diag_missing_trace_dispatch_; 1112 unsigned diag_missing_trace_dispatch_;
1077 unsigned diag_missing_finalize_dispatch_; 1113 unsigned diag_missing_finalize_dispatch_;
1114 unsigned diag_derives_non_stack_allocated_;
1078 1115
1079 unsigned diag_field_requires_tracing_note_; 1116 unsigned diag_field_requires_tracing_note_;
1080 unsigned diag_raw_ptr_to_gc_managed_class_note_; 1117 unsigned diag_raw_ptr_to_gc_managed_class_note_;
1081 unsigned diag_ref_ptr_to_gc_managed_class_note_; 1118 unsigned diag_ref_ptr_to_gc_managed_class_note_;
1082 unsigned diag_own_ptr_to_gc_managed_class_note_; 1119 unsigned diag_own_ptr_to_gc_managed_class_note_;
1120 unsigned diag_stack_allocated_field_note_;
1083 unsigned diag_part_object_contains_gc_root_note_; 1121 unsigned diag_part_object_contains_gc_root_note_;
1084 unsigned diag_field_contains_gc_root_note_; 1122 unsigned diag_field_contains_gc_root_note_;
1085 unsigned diag_finalized_field_note_; 1123 unsigned diag_finalized_field_note_;
1086 unsigned diag_user_declared_destructor_note_; 1124 unsigned diag_user_declared_destructor_note_;
1087 unsigned diag_user_declared_finalizer_note_; 1125 unsigned diag_user_declared_finalizer_note_;
1088 unsigned diag_base_requires_finalization_note_; 1126 unsigned diag_base_requires_finalization_note_;
1089 unsigned diag_field_requires_finalization_note_; 1127 unsigned diag_field_requires_finalization_note_;
1090 unsigned diag_overridden_non_virtual_trace_note_; 1128 unsigned diag_overridden_non_virtual_trace_note_;
1091 unsigned diag_manual_dispatch_method_note_; 1129 unsigned diag_manual_dispatch_method_note_;
1092 1130
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1125 1163
1126 private: 1164 private:
1127 BlinkGCPluginOptions options_; 1165 BlinkGCPluginOptions options_;
1128 }; 1166 };
1129 1167
1130 } // namespace 1168 } // namespace
1131 1169
1132 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X( 1170 static FrontendPluginRegistry::Add<BlinkGCPluginAction> X(
1133 "blink-gc-plugin", 1171 "blink-gc-plugin",
1134 "Check Blink GC invariants"); 1172 "Check Blink GC invariants");
OLDNEW
« no previous file with comments | « no previous file | tools/clang/blink_gc_plugin/RecordInfo.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698