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

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

Issue 192933002: Check that classes with non-trivial destructors have finalization support. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: comments 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
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 #include "Config.h" 5 #include "Config.h"
6 #include "RecordInfo.h" 6 #include "RecordInfo.h"
7 7
8 #include "clang/AST/Attr.h" 8 #include "clang/AST/Attr.h"
9 9
10 using namespace clang; 10 using namespace clang;
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
106 it != base_paths_->end(); 106 it != base_paths_->end();
107 ++it) { 107 ++it) {
108 const CXXBasePathElement& elem = (*it)[it->size() - 1]; 108 const CXXBasePathElement& elem = (*it)[it->size() - 1];
109 CXXRecordDecl* base = elem.Base->getType()->getAsCXXRecordDecl(); 109 CXXRecordDecl* base = elem.Base->getType()->getAsCXXRecordDecl();
110 if (Config::IsGCFinalizedBase(base->getName())) 110 if (Config::IsGCFinalizedBase(base->getName()))
111 return true; 111 return true;
112 } 112 }
113 return false; 113 return false;
114 } 114 }
115 115
116 // A mixin has not yet been "mixed in" if its only GC base is the mixin base.
117 bool RecordInfo::IsUnmixedGCMixin() {
118 if (!IsGCDerived() || base_paths_->begin() == base_paths_->end())
119 return false;
120 // Get the last element of the first path.
121 CXXBasePaths::paths_iterator it = base_paths_->begin();
122 const CXXBasePathElement& elem = (*it)[it->size() - 1];
123 CXXRecordDecl* base = elem.Base->getType()->getAsCXXRecordDecl();
124 // If it is not a mixin base we are done.
125 if (!Config::IsGCMixinBase(base->getName()))
126 return false;
127 // Otherwise, this is unmixed if there are no other paths to GC bases.
128 return ++it == base_paths_->end();
129 }
130
116 // Test if a record is allocated on the managed heap. 131 // Test if a record is allocated on the managed heap.
117 bool RecordInfo::IsGCAllocated() { 132 bool RecordInfo::IsGCAllocated() {
118 return IsGCDerived() || IsHeapAllocatedCollection(); 133 return IsGCDerived() || IsHeapAllocatedCollection();
119 } 134 }
120 135
121 static bool IsAnnotated(Decl* decl, const string& anno) { 136 static bool IsAnnotated(Decl* decl, const string& anno) {
122 AnnotateAttr* attr = decl->getAttr<AnnotateAttr>(); 137 AnnotateAttr* attr = decl->getAttr<AnnotateAttr>();
123 return attr && (attr->getAnnotation() == anno); 138 return attr && (attr->getAnnotation() == anno);
124 } 139 }
125 140
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
164 for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) { 179 for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) {
165 if (it->second.info()->InheritsNonPureTrace()) 180 if (it->second.info()->InheritsNonPureTrace())
166 return true; 181 return true;
167 } 182 }
168 return false; 183 return false;
169 } 184 }
170 185
171 RecordInfo::Bases* RecordInfo::CollectBases() { 186 RecordInfo::Bases* RecordInfo::CollectBases() {
172 // Compute the collection locally to avoid inconsistent states. 187 // Compute the collection locally to avoid inconsistent states.
173 Bases* bases = new Bases; 188 Bases* bases = new Bases;
189 if (!record_->hasDefinition())
190 return bases;
174 for (CXXRecordDecl::base_class_iterator it = record_->bases_begin(); 191 for (CXXRecordDecl::base_class_iterator it = record_->bases_begin();
175 it != record_->bases_end(); 192 it != record_->bases_end();
176 ++it) { 193 ++it) {
177 if (CXXRecordDecl* base = it->getType()->getAsCXXRecordDecl()) { 194 const CXXBaseSpecifier& spec = *it;
178 RecordInfo* info = cache_->Lookup(base); 195 RecordInfo* info = cache_->Lookup(spec.getType());
179 TracingStatus status = info->InheritsNonPureTrace() 196 if (!info)
180 ? TracingStatus::Needed() 197 continue;
181 : TracingStatus::Unneeded(); 198 CXXRecordDecl* base = info->record();
182 bases->insert(std::make_pair(base, BasePoint(info, status))); 199 TracingStatus status = info->InheritsNonPureTrace()
183 } 200 ? TracingStatus::Needed()
201 : TracingStatus::Unneeded();
202 bases->insert(std::make_pair(base, BasePoint(spec, info, status)));
184 } 203 }
185 return bases; 204 return bases;
186 } 205 }
187 206
188 RecordInfo::Fields& RecordInfo::GetFields() { 207 RecordInfo::Fields& RecordInfo::GetFields() {
189 if (!fields_) 208 if (!fields_)
190 fields_ = CollectFields(); 209 fields_ = CollectFields();
191 return *fields_; 210 return *fields_;
192 } 211 }
193 212
194 RecordInfo::Fields* RecordInfo::CollectFields() { 213 RecordInfo::Fields* RecordInfo::CollectFields() {
195 // Compute the collection locally to avoid inconsistent states. 214 // Compute the collection locally to avoid inconsistent states.
196 Fields* fields = new Fields; 215 Fields* fields = new Fields;
216 if (!record_->hasDefinition())
217 return fields;
197 TracingStatus fields_status = TracingStatus::Unneeded(); 218 TracingStatus fields_status = TracingStatus::Unneeded();
198 for (RecordDecl::field_iterator it = record_->field_begin(); 219 for (RecordDecl::field_iterator it = record_->field_begin();
199 it != record_->field_end(); 220 it != record_->field_end();
200 ++it) { 221 ++it) {
201 FieldDecl* field = *it; 222 FieldDecl* field = *it;
202 // Ignore fields annotated with the NO_TRACE_CHECKING macro. 223 // Ignore fields annotated with the NO_TRACE_CHECKING macro.
203 if (IsAnnotated(field, "blink_no_trace_checking")) 224 if (IsAnnotated(field, "blink_no_trace_checking"))
204 continue; 225 continue;
205 if (Edge* edge = CreateEdge(field->getType().getTypePtrOrNull())) { 226 if (Edge* edge = CreateEdge(field->getType().getTypePtrOrNull())) {
206 fields->insert(std::make_pair(field, FieldPoint(field, edge))); 227 fields->insert(std::make_pair(field, FieldPoint(field, edge)));
(...skipping 27 matching lines...) Expand all
234 trace_method_ = traceAfterDispatch; 255 trace_method_ = traceAfterDispatch;
235 trace_dispatch_method_ = trace; 256 trace_dispatch_method_ = trace;
236 } else { 257 } else {
237 // TODO: Can we never have a dispatch method called trace without the same 258 // TODO: Can we never have a dispatch method called trace without the same
238 // class defining a traceAfterDispatch method? 259 // class defining a traceAfterDispatch method?
239 trace_method_ = trace; 260 trace_method_ = trace;
240 trace_dispatch_method_ = 0; 261 trace_dispatch_method_ = 0;
241 } 262 }
242 } 263 }
243 264
265 // TODO: Add classes with a finalize() method that specialize FinalizerTrait.
266 bool RecordInfo::NeedsFinalization() {
267 return record_->hasNonTrivialDestructor();
268 }
269
244 // A class needs tracing if: 270 // A class needs tracing if:
245 // - it is allocated on the managed heap, 271 // - it is allocated on the managed heap,
246 // - it defines a trace method (of the proper signature), or 272 // - it is derived from a class that needs tracing, or
247 // - it contains fields that need tracing. 273 // - it contains fields that need tracing.
274 // TODO: Defining NeedsTracing based on whether a class defines a trace method
275 // (of the proper signature) over approximates too much. The use of transition
276 // types causes some classes to have trace methods without them needing to be
277 // traced.
248 TracingStatus RecordInfo::NeedsTracing(Edge::NeedsTracingOption option) { 278 TracingStatus RecordInfo::NeedsTracing(Edge::NeedsTracingOption option) {
249 if (IsGCAllocated() || GetTraceMethod()) 279 if (IsGCAllocated())
250 return TracingStatus::Needed(); 280 return TracingStatus::Needed();
251 281
282 for (Bases::iterator it = GetBases().begin(); it != GetBases().end(); ++it) {
283 if (it->second.info()->NeedsTracing(option).IsNeeded())
284 return TracingStatus::Needed();
285 }
286
252 if (option == Edge::kRecursive) 287 if (option == Edge::kRecursive)
253 GetFields(); 288 GetFields();
254 289
255 return fields_need_tracing_; 290 return fields_need_tracing_;
256 } 291 }
257 292
258 Edge* RecordInfo::CreateEdge(const Type* type) { 293 Edge* RecordInfo::CreateEdge(const Type* type) {
259 if (!type) { 294 if (!type) {
260 return 0; 295 return 0;
261 } 296 }
262 297
263 if (type->isPointerType()) { 298 if (type->isPointerType()) {
264 if (Edge* ptr = CreateEdge(type->getPointeeType().getTypePtrOrNull())) 299 if (Edge* ptr = CreateEdge(type->getPointeeType().getTypePtrOrNull()))
265 return new RawPtr(ptr); 300 return new RawPtr(ptr);
266 return 0; 301 return 0;
267 } 302 }
268 303
269 CXXRecordDecl* record = type->getAsCXXRecordDecl(); 304 RecordInfo* info = cache_->Lookup(type);
270 305
271 // If the type is neither a pointer or a C++ record we ignore it. 306 // If the type is neither a pointer or a C++ record we ignore it.
272 if (!record) { 307 if (!info) {
273 return 0; 308 return 0;
274 } 309 }
275 310
276 RecordInfo* info = cache_->Lookup(record);
277
278 TemplateArgs args; 311 TemplateArgs args;
279 312
280 if (Config::IsRawPtr(info->name()) && info->GetTemplateArgs(1, &args)) { 313 if (Config::IsRawPtr(info->name()) && info->GetTemplateArgs(1, &args)) {
281 if (Edge* ptr = CreateEdge(args[0])) 314 if (Edge* ptr = CreateEdge(args[0]))
282 return new RawPtr(ptr); 315 return new RawPtr(ptr);
283 return 0; 316 return 0;
284 } 317 }
285 318
286 if (Config::IsRefPtr(info->name()) && info->GetTemplateArgs(1, &args)) { 319 if (Config::IsRefPtr(info->name()) && info->GetTemplateArgs(1, &args)) {
287 if (Edge* ptr = CreateEdge(args[0])) 320 if (Edge* ptr = CreateEdge(args[0]))
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 return 0; 354 return 0;
322 } 355 }
323 356
324 if (Config::IsGCCollection(info->name()) || 357 if (Config::IsGCCollection(info->name()) ||
325 Config::IsWTFCollection(info->name())) { 358 Config::IsWTFCollection(info->name())) {
326 bool is_root = Config::IsPersistentGCCollection(info->name()); 359 bool is_root = Config::IsPersistentGCCollection(info->name());
327 bool on_heap = is_root || info->IsHeapAllocatedCollection(); 360 bool on_heap = is_root || info->IsHeapAllocatedCollection();
328 size_t count = Config::CollectionDimension(info->name()); 361 size_t count = Config::CollectionDimension(info->name());
329 if (!info->GetTemplateArgs(count, &args)) 362 if (!info->GetTemplateArgs(count, &args))
330 return 0; 363 return 0;
331 Collection* edge = new Collection(on_heap, is_root); 364 Collection* edge = new Collection(info, on_heap, is_root);
332 for (TemplateArgs::iterator it = args.begin(); it != args.end(); ++it) { 365 for (TemplateArgs::iterator it = args.begin(); it != args.end(); ++it) {
333 if (Edge* member = CreateEdge(*it)) { 366 if (Edge* member = CreateEdge(*it)) {
334 edge->members().push_back(member); 367 edge->members().push_back(member);
335 } else { 368 } else {
336 // We failed to create an edge so abort the entire edge construction. 369 // We failed to create an edge so abort the entire edge construction.
337 delete edge; // Will delete the already allocated members. 370 delete edge; // Will delete the already allocated members.
338 return 0; 371 return 0;
339 } 372 }
340 } 373 }
341 return edge; 374 return edge;
342 } 375 }
343 376
344 return new Value(info); 377 return new Value(info);
345 } 378 }
OLDNEW
« no previous file with comments | « tools/clang/blink_gc_plugin/RecordInfo.h ('k') | tools/clang/blink_gc_plugin/tests/class_requires_finalization_base.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698