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

Side by Side Diff: tools/gcmole/gcmole.cc

Issue 6973063: Extend GCMole with poor man's data flow analysis to catch dead raw pointer vars. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 7 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 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 62
63 return false; 63 return false;
64 } 64 }
65 65
66 66
67 static bool InV8Namespace(const clang::NamedDecl* decl) { 67 static bool InV8Namespace(const clang::NamedDecl* decl) {
68 return decl->getQualifiedNameAsString().compare(0, 4, "v8::") == 0; 68 return decl->getQualifiedNameAsString().compare(0, 4, "v8::") == 0;
69 } 69 }
70 70
71 71
72 struct Resolver {
73 explicit Resolver(clang::ASTContext& ctx)
74 : ctx_(ctx), decl_ctx_(ctx.getTranslationUnitDecl()) {
75 }
76
77 Resolver(clang::ASTContext& ctx, clang::DeclContext* decl_ctx)
78 : ctx_(ctx), decl_ctx_(decl_ctx) {
79 }
80
81 clang::DeclarationName ResolveName(const char* n) {
82 clang::IdentifierInfo* ident = &ctx_.Idents.get(n);
83 return ctx_.DeclarationNames.getIdentifier(ident);
84 }
85
86 Resolver ResolveNamespace(const char* n) {
87 return Resolver(ctx_, Resolve<clang::NamespaceDecl>(n));
88 }
89
90 template<typename T>
91 T* Resolve(const char* n) {
92 if (decl_ctx_ == NULL) return NULL;
93
94 clang::DeclContext::lookup_result result =
95 decl_ctx_->lookup(ResolveName(n));
96
97 for (clang::DeclContext::lookup_iterator i = result.first,
98 e = result.second;
Mads Ager (chromium) 2011/05/16 06:10:27 How about extracting result.second before the loop
99 i != e;
100 i++) {
101 if (isa<T>(*i)) return cast<T>(*i);
102 }
103
104 return NULL;
105 }
106
107 private:
108 clang::ASTContext& ctx_;
109 clang::DeclContext* decl_ctx_;
110 };
111
112
72 class CalleesPrinter : public clang::RecursiveASTVisitor<CalleesPrinter> { 113 class CalleesPrinter : public clang::RecursiveASTVisitor<CalleesPrinter> {
73 public: 114 public:
74 explicit CalleesPrinter(clang::MangleContext* ctx) : ctx_(ctx) { 115 explicit CalleesPrinter(clang::MangleContext* ctx) : ctx_(ctx) {
75 } 116 }
76 117
77 virtual bool VisitCallExpr(clang::CallExpr* expr) { 118 virtual bool VisitCallExpr(clang::CallExpr* expr) {
78 const clang::FunctionDecl* callee = expr->getDirectCallee(); 119 const clang::FunctionDecl* callee = expr->getDirectCallee();
79 if (callee != NULL) AnalyzeFunction(callee); 120 if (callee != NULL) AnalyzeFunction(callee);
80 return true; 121 return true;
81 } 122 }
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 } 174 }
134 } 175 }
135 176
136 private: 177 private:
137 clang::MangleContext* ctx_; 178 clang::MangleContext* ctx_;
138 179
139 std::stack<CalleesSet* > scopes_; 180 std::stack<CalleesSet* > scopes_;
140 Callgraph callgraph_; 181 Callgraph callgraph_;
141 }; 182 };
142 183
184
143 class FunctionDeclarationFinder 185 class FunctionDeclarationFinder
144 : public clang::ASTConsumer, 186 : public clang::ASTConsumer,
145 public clang::RecursiveASTVisitor<FunctionDeclarationFinder> { 187 public clang::RecursiveASTVisitor<FunctionDeclarationFinder> {
146 public: 188 public:
147 explicit FunctionDeclarationFinder(clang::Diagnostic& d, 189 explicit FunctionDeclarationFinder(clang::Diagnostic& d,
148 clang::SourceManager& sm) 190 clang::SourceManager& sm,
191 const std::vector<std::string>& args)
149 : d_(d), sm_(sm) { } 192 : d_(d), sm_(sm) { }
150 193
151 virtual void HandleTranslationUnit(clang::ASTContext &ctx) { 194 virtual void HandleTranslationUnit(clang::ASTContext &ctx) {
152 mangle_context_ = clang::createItaniumMangleContext(ctx, d_); 195 mangle_context_ = clang::createItaniumMangleContext(ctx, d_);
153 callees_printer_ = new CalleesPrinter(mangle_context_); 196 callees_printer_ = new CalleesPrinter(mangle_context_);
154 197
155 TraverseDecl(ctx.getTranslationUnitDecl()); 198 TraverseDecl(ctx.getTranslationUnitDecl());
156 199
157 callees_printer_->PrintCallGraph(); 200 callees_printer_->PrintCallGraph();
158 } 201 }
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 238
196 MangledName name; 239 MangledName name;
197 if (GetMangledName(ctx, decl, &name)) { 240 if (GetMangledName(ctx, decl, &name)) {
198 return gc_suspects.find(name) != gc_suspects.end(); 241 return gc_suspects.find(name) != gc_suspects.end();
199 } 242 }
200 243
201 return false; 244 return false;
202 } 245 }
203 246
204 247
205 static bool IsHandleType(const clang::DeclarationName& handleDeclName, 248 static const int kNoEffect = 0;
206 const clang::QualType& qtype) { 249 static const int kCausesGC = 1;
207 const clang::Type* canonical_type = 250 static const int kRawDef = 2;
208 qtype.getTypePtr()->getCanonicalTypeUnqualified().getTypePtr(); 251 static const int kRawUse = 4;
209 252 static const int kAllEffects = kCausesGC | kRawDef | kRawUse;
210 if (const clang::TemplateSpecializationType* type = 253
211 canonical_type->getAs<clang::TemplateSpecializationType>()) { 254 class Environment;
212 if (clang::TemplateDecl* decl = 255
213 type->getTemplateName().getAsTemplateDecl()) { 256 class ExprEffect {
214 if (decl->getTemplatedDecl()->getDeclName() == handleDeclName) { 257 public:
258 bool hasGC() { return (effect_ & kCausesGC) != 0; }
259 void setGC() { effect_ |= kCausesGC; }
260
261 bool hasRawDef() { return (effect_ & kRawDef) != 0; }
262 void setRawDef() { effect_ |= kRawDef; }
263
264 bool hasRawUse() { return (effect_ & kRawUse) != 0; }
265 void setRawUse() { effect_ |= kRawUse; }
266
267 static ExprEffect None() { return ExprEffect(kNoEffect, NULL); }
268 static ExprEffect NoneWithEnv(Environment* env) {
269 return ExprEffect(kNoEffect, env);
270 }
271 static ExprEffect RawUse() { return ExprEffect(kRawUse, NULL); }
272
273 static ExprEffect Merge(ExprEffect a, ExprEffect b);
274 static ExprEffect MergeSeq(ExprEffect a, ExprEffect b);
275 ExprEffect Define(const std::string& name);
276
277 Environment* env() {
278 return reinterpret_cast<Environment*>(effect_ & ~kAllEffects);
279 }
280
281 private:
282 ExprEffect(int effect, Environment* env)
283 : effect_((effect & kAllEffects) |
284 reinterpret_cast<intptr_t>(env)) { }
285
286 intptr_t effect_;
287 };
288
289
290 const std::string BAD_EXPR_MSG("Possible problem with evaluation order.");
291 const std::string DEAD_VAR_MSG("Possibly dead variable.");
292
293
294 class Environment {
295 public:
296 Environment() { }
297
298 static Environment Unreachable() {
299 Environment env;
300 env.live_.set();
301 return env;
302 }
303
304 static Environment Merge(const Environment& l,
305 const Environment& r) {
306 return Environment(l, r);
307 }
308
309 Environment ApplyEffect(ExprEffect effect) const {
310 Environment out = effect.hasGC() ? Environment() : Environment(*this);
311 if (effect.env() != NULL) out.live_ |= effect.env()->live_;
312 return out;
313 }
314
315 typedef std::map<std::string, int> SymbolTable;
316
317 bool IsAlive(const std::string& name) const {
318 SymbolTable::iterator code = symbol_table_.find(name);
319 if (code == symbol_table_.end()) return false;
320 return live_[code->second];
321 }
322
323 bool Equal(const Environment& env) {
324 return live_ == env.live_;
325 }
326
327 Environment Define(const std::string& name) const {
328 return Environment(*this, SymbolToCode(name));
329 }
330
331 void MDefine(const std::string& name) {
332 live_.set(SymbolToCode(name));
333 }
334
335 static int SymbolToCode(const std::string& name) {
336 SymbolTable::iterator code = symbol_table_.find(name);
337
338 if (code == symbol_table_.end()) {
339 int new_code = symbol_table_.size();
340 symbol_table_.insert(std::make_pair(name, new_code));
341 return new_code;
342 }
343
344 return code->second;
345 }
346
347 static void ClearSymbolTable() {
348 for (std::vector<Environment*>::iterator i = envs_.begin(),
349 end = envs_.end();
350 i != end;
Mads Ager (chromium) 2011/05/16 06:10:27 Move envs_.end() here to make code more readable?
351 ++i) {
352 delete *i;
353 }
354 envs_.clear();
355 symbol_table_.clear();
356 }
357
358 void Print() const {
359 bool comma = false;
360 std::cout << "{";
361 for (SymbolTable::iterator i = symbol_table_.begin(),
362 end = symbol_table_.end();
363 i != end;
Mads Ager (chromium) 2011/05/16 06:10:27 Ditto. Also multiple places below.
364 ++i) {
365 if (live_[i->second]) {
366 if (comma) std::cout << ", ";
367 std::cout << i->first;
368 comma = true;
369 }
370 }
371 std::cout << "}";
372 }
373
374 static Environment* Allocate(const Environment& env) {
375 Environment* allocated_env = new Environment(env);
376 envs_.push_back(allocated_env);
377 return allocated_env;
378 }
379
380 private:
381 Environment(const Environment& l, const Environment& r)
382 : live_(l.live_ & r.live_) {
383 }
384
385 Environment(const Environment& l, int code)
386 : live_(l.live_) {
387 live_.set(code);
388 }
389
390 static SymbolTable symbol_table_;
391 static std::vector<Environment* > envs_;
392
393 static const int kMaxNumberOfLocals = 256;
394 std::bitset<kMaxNumberOfLocals> live_;
395
396 friend class ExprEffect;
397 friend class CallProps;
398 };
399
400
401 class CallProps {
402 public:
403 CallProps() : env_(NULL) { }
404
405 void SetEffect(int arg, ExprEffect in) {
406 if (in.hasGC()) gc_.set(arg);
407 if (in.hasRawDef()) raw_def_.set(arg);
408 if (in.hasRawUse()) raw_use_.set(arg);
409 if (in.env() != NULL) {
410 if (env_ == NULL) env_ = in.env();
411 env_->live_ |= in.env()->live_;
412 }
413 }
414
415 ExprEffect ComputeCumulativeEffect(bool result_is_raw) {
416 ExprEffect out = ExprEffect::NoneWithEnv(env_);
417 if (gc_.any()) out.setGC();
418 if (raw_use_.any()) out.setRawUse();
419 if (result_is_raw) out.setRawDef();
420 return out;
421 }
422
423 bool IsSafe() {
424 if (!gc_.any()) return true;
425 std::bitset<kMaxNumberOfArguments> raw = (raw_def_ | raw_use_);
426 if (!raw.any()) return true;
427 return gc_.count() == 1 && !((raw ^ gc_).any());
428 }
429
430 private:
431 static const int kMaxNumberOfArguments = 64;
432 std::bitset<kMaxNumberOfArguments> raw_def_;
433 std::bitset<kMaxNumberOfArguments> raw_use_;
434 std::bitset<kMaxNumberOfArguments> gc_;
435 Environment* env_;
436 };
437
438
439 Environment::SymbolTable Environment::symbol_table_;
440 std::vector<Environment* > Environment::envs_;
441
442
443 ExprEffect ExprEffect::Merge(ExprEffect a, ExprEffect b) {
444 Environment* a_env = a.env();
445 Environment* b_env = b.env();
446 Environment* out = NULL;
447 if (a_env != NULL && b_env != NULL) {
448 out = Environment::Allocate(*a_env);
449 out->live_ &= b_env->live_;
450 }
451 return ExprEffect(a.effect_ | b.effect_, out);
452 }
453
454
455 ExprEffect ExprEffect::MergeSeq(ExprEffect a, ExprEffect b) {
456 Environment* a_env = b.hasGC() ? NULL : a.env();
457 Environment* b_env = b.env();
458 Environment* out = (b_env == NULL) ? a_env : b_env;
459 if (a_env != NULL && b_env != NULL) {
460 out = Environment::Allocate(*b_env);
461 out->live_ |= a_env->live_;
462 }
463 return ExprEffect(a.effect_ | b.effect_, out);
464 }
465
466
467 ExprEffect ExprEffect::Define(const std::string& name) {
468 Environment* e = env();
469 if (e == NULL) {
470 e = Environment::Allocate(Environment());
471 }
472 e->MDefine(name);
473 return ExprEffect(effect_, e);
474 }
475
476
477 static std::string THIS ("this");
478
479
480 class FunctionAnalyzer {
481 public:
482 FunctionAnalyzer(clang::MangleContext* ctx,
483 clang::DeclarationName handleDeclName,
484 clang::CXXRecordDecl* objectDecl,
485 clang::CXXRecordDecl* smiDecl,
486 clang::Diagnostic& d,
487 clang::SourceManager& sm,
488 bool dead_vars_analysis)
489 : ctx_(ctx),
490 handleDeclName_(handleDeclName),
491 objectDecl_(objectDecl),
492 smiDecl_(smiDecl),
493 d_(d),
494 sm_(sm),
495 block_(NULL),
496 dead_vars_analysis_(dead_vars_analysis) {
497 }
498
499
500 // --------------------------------------------------------------------------
501 // Expressions
502 // --------------------------------------------------------------------------
503
504 ExprEffect VisitExpr(clang::Expr* expr, const Environment& env) {
505 #define VISIT(type) do { \
506 clang::type * concrete_expr = dyn_cast_or_null<clang::type>(expr); \
Mads Ager (chromium) 2011/05/16 06:10:27 Placement of '*'.
507 if (concrete_expr != NULL) { \
508 return Visit##type (concrete_expr, env); \
509 } \
510 } while(0);
511
512 VISIT(AbstractConditionalOperator);
513 VISIT(AddrLabelExpr);
514 VISIT(ArraySubscriptExpr);
515 VISIT(BinaryOperator);
516 VISIT(BinaryTypeTraitExpr);
517 VISIT(BlockDeclRefExpr);
518 VISIT(BlockExpr);
519 VISIT(CallExpr);
520 VISIT(CastExpr);
521 VISIT(CharacterLiteral);
522 VISIT(ChooseExpr);
523 VISIT(CompoundLiteralExpr);
524 VISIT(CXXBindTemporaryExpr);
525 VISIT(CXXBoolLiteralExpr);
526 VISIT(CXXConstructExpr);
527 VISIT(CXXDefaultArgExpr);
528 VISIT(CXXDeleteExpr);
529 VISIT(CXXDependentScopeMemberExpr);
530 VISIT(CXXNewExpr);
531 VISIT(CXXNoexceptExpr);
532 VISIT(CXXNullPtrLiteralExpr);
533 VISIT(CXXPseudoDestructorExpr);
534 VISIT(CXXScalarValueInitExpr);
535 VISIT(CXXThisExpr);
536 VISIT(CXXThrowExpr);
537 VISIT(CXXTypeidExpr);
538 VISIT(CXXUnresolvedConstructExpr);
539 VISIT(CXXUuidofExpr);
540 VISIT(DeclRefExpr);
541 VISIT(DependentScopeDeclRefExpr);
542 VISIT(DesignatedInitExpr);
543 VISIT(ExprWithCleanups);
544 VISIT(ExtVectorElementExpr);
545 VISIT(FloatingLiteral);
546 VISIT(GNUNullExpr);
547 VISIT(ImaginaryLiteral);
548 VISIT(ImplicitValueInitExpr);
549 VISIT(InitListExpr);
550 VISIT(IntegerLiteral);
551 VISIT(MemberExpr);
552 VISIT(OffsetOfExpr);
553 VISIT(OpaqueValueExpr);
554 VISIT(OverloadExpr);
555 VISIT(PackExpansionExpr);
556 VISIT(ParenExpr);
557 VISIT(ParenListExpr);
558 VISIT(PredefinedExpr);
559 VISIT(ShuffleVectorExpr);
560 VISIT(SizeOfPackExpr);
561 VISIT(StmtExpr);
562 VISIT(StringLiteral);
563 VISIT(SubstNonTypeTemplateParmPackExpr);
564 VISIT(UnaryExprOrTypeTraitExpr);
565 VISIT(UnaryOperator);
566 VISIT(UnaryTypeTraitExpr);
567 VISIT(VAArgExpr);
568 #undef VISIT
569
570 return ExprEffect::None();
571 }
572
573 #define DECL_VISIT_EXPR(type) \
574 ExprEffect Visit##type (clang::type * expr, const Environment& env)
575
576 #define IGNORE_EXPR(type) \
577 ExprEffect Visit##type (clang::type * expr, const Environment& env) { \
578 return ExprEffect::None(); \
579 }
580
581 IGNORE_EXPR(AddrLabelExpr);
582 IGNORE_EXPR(BinaryTypeTraitExpr);
583 IGNORE_EXPR(BlockExpr);
584 IGNORE_EXPR(CharacterLiteral);
585 IGNORE_EXPR(ChooseExpr);
586 IGNORE_EXPR(CompoundLiteralExpr);
587 IGNORE_EXPR(CXXBoolLiteralExpr);
588 IGNORE_EXPR(CXXDependentScopeMemberExpr);
589 IGNORE_EXPR(CXXNullPtrLiteralExpr);
590 IGNORE_EXPR(CXXPseudoDestructorExpr);
591 IGNORE_EXPR(CXXScalarValueInitExpr);
592 IGNORE_EXPR(CXXNoexceptExpr);
593 IGNORE_EXPR(CXXTypeidExpr);
594 IGNORE_EXPR(CXXUnresolvedConstructExpr);
595 IGNORE_EXPR(CXXUuidofExpr);
596 IGNORE_EXPR(DependentScopeDeclRefExpr);
597 IGNORE_EXPR(DesignatedInitExpr);
598 IGNORE_EXPR(ExtVectorElementExpr);
599 IGNORE_EXPR(FloatingLiteral);
600 IGNORE_EXPR(ImaginaryLiteral);
601 IGNORE_EXPR(IntegerLiteral);
602 IGNORE_EXPR(OffsetOfExpr);
603 IGNORE_EXPR(ImplicitValueInitExpr);
604 IGNORE_EXPR(PackExpansionExpr);
605 IGNORE_EXPR(PredefinedExpr);
606 IGNORE_EXPR(ShuffleVectorExpr);
607 IGNORE_EXPR(SizeOfPackExpr);
608 IGNORE_EXPR(StmtExpr);
609 IGNORE_EXPR(StringLiteral);
610 IGNORE_EXPR(SubstNonTypeTemplateParmPackExpr);
611 IGNORE_EXPR(UnaryExprOrTypeTraitExpr);
612 IGNORE_EXPR(UnaryTypeTraitExpr);
613 IGNORE_EXPR(VAArgExpr);
614 IGNORE_EXPR(GNUNullExpr);
615 IGNORE_EXPR(OverloadExpr);
616
617 DECL_VISIT_EXPR(CXXThisExpr) {
618 return Use(expr, expr->getType(), THIS, env);
619 }
620
621 DECL_VISIT_EXPR(AbstractConditionalOperator) {
622 Environment after_cond = env.ApplyEffect(VisitExpr(expr->getCond(), env));
623 return ExprEffect::Merge(VisitExpr(expr->getTrueExpr(), after_cond),
624 VisitExpr(expr->getFalseExpr(), after_cond));
625 }
626
627 DECL_VISIT_EXPR(ArraySubscriptExpr) {
628 clang::Expr* exprs[2] = {expr->getBase(), expr->getIdx()};
629 return Par(expr, 2, exprs, env);
630 }
631
632 bool IsRawPointerVar(clang::Expr* expr, std::string* var_name) {
633 if (isa<clang::BlockDeclRefExpr>(expr)) {
634 *var_name = cast<clang::BlockDeclRefExpr>(expr)->getDecl()->
635 getNameAsString();
636 return true;
637 } else if (isa<clang::DeclRefExpr>(expr)) {
638 *var_name = cast<clang::DeclRefExpr>(expr)->getDecl()->getNameAsString();
639 return true;
640 }
641 return false;
642 }
643
644 DECL_VISIT_EXPR(BinaryOperator) {
645 clang::Expr* lhs = expr->getLHS();
646 clang::Expr* rhs = expr->getRHS();
647 clang::Expr* exprs[2] = {lhs, rhs};
648
649 switch (expr->getOpcode()) {
650 case clang::BO_Comma:
651 return Seq(expr, 2, exprs, env);
652
653 case clang::BO_LAnd:
654 case clang::BO_LOr:
655 return ExprEffect::Merge(VisitExpr(lhs, env), VisitExpr(rhs, env));
656
657 case clang::BO_Assign: {
658 std::string var_name;
659 if (IsRawPointerVar(lhs, &var_name)) {
660 return VisitExpr(rhs, env).Define(var_name);
661 }
662 return Par(expr, 2, exprs, env);
663 }
664
665 default:
666 return Par(expr, 2, exprs, env);
667 }
668 }
669
670 DECL_VISIT_EXPR(CXXBindTemporaryExpr) {
671 return VisitExpr(expr->getSubExpr(), env);
672 }
673
674 DECL_VISIT_EXPR(CXXConstructExpr) {
675 return VisitArguments<>(expr, env);
676 }
677
678 DECL_VISIT_EXPR(CXXDefaultArgExpr) {
679 return VisitExpr(expr->getExpr(), env);
680 }
681
682 DECL_VISIT_EXPR(CXXDeleteExpr) {
683 return VisitExpr(expr->getArgument(), env);
684 }
685
686 DECL_VISIT_EXPR(CXXNewExpr) {
687 return Par(expr,
688 expr->getNumConstructorArgs(),
689 expr->getConstructorArgs(),
690 env);
691 }
692
693 DECL_VISIT_EXPR(ExprWithCleanups) {
694 return VisitExpr(expr->getSubExpr(), env);
695 }
696
697 DECL_VISIT_EXPR(CXXThrowExpr) {
698 return VisitExpr(expr->getSubExpr(), env);
699 }
700
701 DECL_VISIT_EXPR(InitListExpr) {
702 return Seq(expr, expr->getNumInits(), expr->getInits(), env);
703 }
704
705 DECL_VISIT_EXPR(MemberExpr) {
706 return VisitExpr(expr->getBase(), env);
707 }
708
709 DECL_VISIT_EXPR(OpaqueValueExpr) {
710 return VisitExpr(expr->getSourceExpr(), env);
711 }
712
713 DECL_VISIT_EXPR(ParenExpr) {
714 return VisitExpr(expr->getSubExpr(), env);
715 }
716
717 DECL_VISIT_EXPR(ParenListExpr) {
718 return Par(expr, expr->getNumExprs(), expr->getExprs(), env);
719 }
720
721 DECL_VISIT_EXPR(UnaryOperator) {
722 // TODO We are treating all expressions that look like &raw_pointer_var
723 // as definitions of raw_pointer_var. This should be changed to
724 // recognize less generic pattern:
725 //
726 // if (maybe_object->ToObject(&obj)) return maybe_object;
727 //
728 if (expr->getOpcode() == clang::UO_AddrOf) {
729 std::string var_name;
730 if (IsRawPointerVar(expr->getSubExpr(), &var_name)) {
731 return ExprEffect::None().Define(var_name);
732 }
733 }
734 return VisitExpr(expr->getSubExpr(), env);
735 }
736
737 DECL_VISIT_EXPR(CastExpr) {
738 return VisitExpr(expr->getSubExpr(), env);
739 }
740
741 DECL_VISIT_EXPR(DeclRefExpr) {
742 return Use(expr, expr->getDecl(), env);
743 }
744
745 DECL_VISIT_EXPR(BlockDeclRefExpr) {
746 return Use(expr, expr->getDecl(), env);
747 }
748
749 ExprEffect Par(clang::Expr* parent,
750 int n,
751 clang::Expr** exprs,
752 const Environment& env) {
753 CallProps props;
754
755 for (int i = 0; i < n; ++i) {
756 props.SetEffect(i, VisitExpr(exprs[i], env));
757 }
758
759 if (!props.IsSafe()) ReportUnsafe(parent, BAD_EXPR_MSG);
760
761 return props.ComputeCumulativeEffect(IsRawPointerType(parent->getType()));
762 }
763
764 ExprEffect Seq(clang::Stmt* parent,
765 int n,
766 clang::Expr** exprs,
767 const Environment& env) {
768 ExprEffect out = ExprEffect::None();
769 Environment out_env = env;
770 for (int i = 0; i < n; ++i) {
771 out = ExprEffect::MergeSeq(out, VisitExpr(exprs[i], out_env));
772 out_env = out_env.ApplyEffect(out);
773 }
774 return out;
775 }
776
777 ExprEffect Use(const clang::Expr* parent,
778 const clang::QualType& var_type,
779 const std::string& var_name,
780 const Environment& env) {
781 if (IsRawPointerType(var_type)) {
782 if (!env.IsAlive(var_name) && dead_vars_analysis_) {
783 ReportUnsafe(parent, DEAD_VAR_MSG);
784 }
785 return ExprEffect::RawUse();
786 }
787 return ExprEffect::None();
788 }
789
790 ExprEffect Use(const clang::Expr* parent,
791 const clang::ValueDecl* var,
792 const Environment& env) {
793 return Use(parent, var->getType(), var->getNameAsString(), env);
794 }
795
796
797 template<typename ExprType>
798 ExprEffect VisitArguments(ExprType* call, const Environment& env) {
799 CallProps props;
800 VisitArguments<>(call, &props, env);
801 if (!props.IsSafe()) ReportUnsafe(call, BAD_EXPR_MSG);
802 return props.ComputeCumulativeEffect(IsRawPointerType(call->getType()));
803 }
804
805 template<typename ExprType>
806 void VisitArguments(ExprType* call,
807 CallProps* props,
808 const Environment& env) {
809 for (unsigned arg = 0; arg < call->getNumArgs(); arg++) {
810 props->SetEffect(arg + 1, VisitExpr(call->getArg(arg), env));
811 }
812 }
813
814
815 ExprEffect VisitCallExpr(clang::CallExpr* call,
816 const Environment& env) {
817 CallProps props;
818
819 clang::CXXMemberCallExpr* memcall =
820 dyn_cast_or_null<clang::CXXMemberCallExpr>(call);
821 if (memcall != NULL) {
822 clang::Expr* receiver = memcall->getImplicitObjectArgument();
823 props.SetEffect(0, VisitExpr(receiver, env));
824 }
825
826 VisitArguments<>(call, &props, env);
827
828 if (!props.IsSafe()) ReportUnsafe(call, BAD_EXPR_MSG);
829
830 ExprEffect out =
831 props.ComputeCumulativeEffect(IsRawPointerType(call->getType()));
832
833 clang::FunctionDecl* callee = call->getDirectCallee();
834 if ((callee != NULL) && KnownToCauseGC(ctx_, callee)) {
835 out.setGC();
836 }
837
838 return out;
839 }
840
841 // --------------------------------------------------------------------------
842 // Statements
843 // --------------------------------------------------------------------------
844
845 Environment VisitStmt(clang::Stmt* stmt, const Environment& env) {
846 #define VISIT(type) do { \
847 clang::type * concrete_stmt = dyn_cast_or_null<clang::type>(stmt); \
848 if (concrete_stmt != NULL) { \
849 return Visit##type (concrete_stmt, env); \
850 } \
851 } while(0);
852
853 if (clang::Expr* expr = dyn_cast_or_null<clang::Expr>(stmt)) {
854 return env.ApplyEffect(VisitExpr(expr, env));
855 }
856
857 VISIT(AsmStmt);
858 VISIT(BreakStmt);
859 VISIT(CompoundStmt);
860 VISIT(ContinueStmt);
861 VISIT(CXXCatchStmt);
862 VISIT(CXXTryStmt);
863 VISIT(DeclStmt);
864 VISIT(DoStmt);
865 VISIT(ForStmt);
866 VISIT(GotoStmt);
867 VISIT(IfStmt);
868 VISIT(IndirectGotoStmt);
869 VISIT(LabelStmt);
870 VISIT(NullStmt);
871 VISIT(ReturnStmt);
872 VISIT(CaseStmt);
873 VISIT(DefaultStmt);
874 VISIT(SwitchStmt);
875 VISIT(WhileStmt);
876 #undef VISIT
877
878 return env;
879 }
880
881 #define DECL_VISIT_STMT(type) \
882 Environment Visit##type (clang::type * stmt, const Environment& env)
Mads Ager (chromium) 2011/05/16 06:10:27 Is there a reason for the '*' placement here and i
883
884 #define IGNORE_STMT(type) \
885 Environment Visit##type (clang::type * stmt, const Environment& env) { \
Mads Ager (chromium) 2011/05/16 06:10:27 If you place the '*' differently the '\' aligns wi
886 return env; \
887 }
888
889 IGNORE_STMT(IndirectGotoStmt);
890 IGNORE_STMT(NullStmt);
891 IGNORE_STMT(AsmStmt);
892
893 // We are ignoring control flow for simplicity.
894 IGNORE_STMT(GotoStmt);
895 IGNORE_STMT(LabelStmt);
896
897 // We are ignoring try/catch because V8 does not use them.
898 IGNORE_STMT(CXXCatchStmt);
899 IGNORE_STMT(CXXTryStmt);
900
901 class Block {
902 public:
903 Block(const Environment& in,
904 FunctionAnalyzer* owner)
905 : in_(in), out_(Environment::Unreachable()), changed_(false), owner_(own er) {
Mads Ager (chromium) 2011/05/16 06:10:27 Long line.
906 parent_ = owner_->EnterBlock(this);
907 }
908
909 ~Block() {
910 owner_->LeaveBlock(parent_);
911 }
912
913 void MergeIn(const Environment& env) {
914 Environment old_in = in_;
915 in_ = Environment::Merge(in_, env);
916 changed_ = !old_in.Equal(in_);
917 }
918
919 bool changed() {
920 if (changed_) {
921 changed_ = false;
215 return true; 922 return true;
216 } 923 }
217 } 924 return false;
218 } else if (const clang::RecordType* type = 925 }
219 canonical_type->getAs<clang::RecordType>()) { 926
220 if (const clang::ClassTemplateSpecializationDecl* t = 927 const Environment& in() {
221 dyn_cast<clang::ClassTemplateSpecializationDecl>(type->getDecl())) { 928 return in_;
222 if (t->getSpecializedTemplate()->getDeclName() == handleDeclName) { 929 }
223 return true; 930
224 } 931 const Environment& out() {
225 } 932 return out_;
226 } 933 }
227 934
228 return false; 935 void MergeOut(const Environment& env) {
229 } 936 out_ = Environment::Merge(out_, env);
230 937 }
231 938
232 class ExpressionClassifier : 939 void Seq(clang::Stmt* a, clang::Stmt* b, clang::Stmt* c) {
233 public clang::RecursiveASTVisitor<ExpressionClassifier> { 940 Environment a_out = owner_->VisitStmt(a, in());
234 public: 941 Environment b_out = owner_->VisitStmt(b, a_out);
235 ExpressionClassifier(clang::DeclarationName handleDeclName, 942 Environment c_out = owner_->VisitStmt(c, b_out);
236 clang::MangleContext* ctx, 943 MergeOut(c_out);
237 clang::CXXRecordDecl* objectDecl) 944 }
238 : handleDeclName_(handleDeclName), 945
239 ctx_(ctx), 946 void Seq(clang::Stmt* a, clang::Stmt* b) {
240 objectDecl_(objectDecl) { 947 Environment a_out = owner_->VisitStmt(a, in());
241 } 948 Environment b_out = owner_->VisitStmt(b, a_out);
242 949 MergeOut(b_out);
243 bool IsBadExpression(clang::Expr* expr) { 950 }
244 has_derefs_ = has_gc_ = false; 951
245 TraverseStmt(expr); 952 void Loop(clang::Stmt* a, clang::Stmt* b, clang::Stmt* c) {
246 return has_derefs_ && has_gc_; 953 Seq(a, b, c);
247 } 954 MergeIn(out());
248 955 }
249 bool IsBadCallSite(clang::Expr* expr) { 956
250 if (isa<clang::CallExpr>(expr)) { 957 void Loop(clang::Stmt* a, clang::Stmt* b) {
251 clang::CallExpr* call = cast<clang::CallExpr>(expr); 958 Seq(a, b);
252 959 MergeIn(out());
253 MarkGCSuspectAsArgument(call); 960 }
254 MarkHandleDereferenceAsArgument(call); 961
255 962
256 return derefs_.any() && 963 private:
257 ((gc_.count() > 1) || (gc_.any() && (gc_ ^ derefs_).any())); 964 Environment in_;
258 } 965 Environment out_;
259 return false; 966 bool changed_;
260 } 967 FunctionAnalyzer* owner_;
261 968 Block* parent_;
262 virtual bool VisitExpr(clang::Expr* expr) { 969 };
263 has_derefs_ = has_derefs_ || IsRawPointerType(expr); 970
264 return !has_gc_ || !has_derefs_; 971
265 } 972 DECL_VISIT_STMT(BreakStmt) {
266 973 block_->MergeOut(env);
267 virtual bool VisitCallExpr(clang::CallExpr* expr) { 974 return Environment::Unreachable();
268 has_gc_ = has_gc_ || CanCauseGC(expr); 975 }
269 return !has_gc_ || !has_derefs_; 976
270 } 977 DECL_VISIT_STMT(ContinueStmt) {
271 private: 978 block_->MergeIn(env);
272 void MarkHandleDereferenceAsArgument(clang::CallExpr* call) { 979 return Environment::Unreachable();
273 derefs_.reset(); 980 }
274 981
275 if (clang::CXXMemberCallExpr* memcall = 982 DECL_VISIT_STMT(CompoundStmt) {
276 dyn_cast<clang::CXXMemberCallExpr>(call)) { 983 Environment out = env;
277 if (ManipulatesRawPointers(memcall->getImplicitObjectArgument())) { 984 for (clang::CompoundStmt::body_iterator s = stmt->body_begin(),
278 derefs_.set(0); 985 end = stmt->body_end();
279 } 986 s != end;
280 } 987 ++s) {
281 988 out = VisitStmt(*s, out);
282 for (unsigned arg = 0; arg < call->getNumArgs(); arg++) { 989 }
283 if (ManipulatesRawPointers(call->getArg(arg))) derefs_.set(arg + 1); 990 return out;
284 } 991 }
285 } 992
286 993 DECL_VISIT_STMT(WhileStmt) {
287 void MarkGCSuspectAsArgument(clang::CallExpr* call) { 994 Block block (env, this);
288 gc_.reset(); 995 do {
289 996 block.Loop(stmt->getCond(), stmt->getBody());
290 clang::CXXMemberCallExpr* memcall = 997 } while (block.changed());
291 dyn_cast_or_null<clang::CXXMemberCallExpr>(call); 998 return block.out();
292 if (memcall != NULL && CanCauseGC(memcall->getImplicitObjectArgument())) { 999 }
293 gc_.set(0); 1000
294 } 1001 DECL_VISIT_STMT(DoStmt) {
295 1002 Block block (env, this);
296 for (unsigned arg = 0; arg < call->getNumArgs(); arg++) { 1003 do {
297 if (CanCauseGC(call->getArg(arg))) gc_.set(arg + 1); 1004 block.Loop(stmt->getBody(), stmt->getCond());
298 } 1005 } while (block.changed());
1006 return block.out();
1007 }
1008
1009 DECL_VISIT_STMT(ForStmt) {
1010 Block block (VisitStmt(stmt->getInit(), env), this);
1011 do {
1012 block.Loop(stmt->getCond(),
Mads Ager (chromium) 2011/05/16 06:10:27 Shouldn't this be Loop(Cond, Body, Inc)?
1013 stmt->getInc(),
1014 stmt->getBody());
1015 } while (block.changed());
1016 return block.out();
1017 }
1018
1019 DECL_VISIT_STMT(IfStmt) {
1020 Environment cond_out = VisitStmt(stmt->getCond(), env);
1021 Environment then_out = VisitStmt(stmt->getThen(), cond_out);
1022 Environment else_out = VisitStmt(stmt->getElse(), cond_out);
1023 return Environment::Merge(then_out, else_out);
1024 }
1025
1026 DECL_VISIT_STMT(SwitchStmt) {
1027 Block block (env, this);
1028 block.Seq(stmt->getCond(), stmt->getBody());
1029 return block.out();
1030 }
1031
1032 DECL_VISIT_STMT(CaseStmt) {
1033 Environment in = Environment::Merge(env, block_->in());
1034 Environment after_lhs = VisitStmt(stmt->getLHS(), in);
1035 return VisitStmt(stmt->getSubStmt(), after_lhs);
1036 }
1037
1038 DECL_VISIT_STMT(DefaultStmt) {
1039 Environment in = Environment::Merge(env, block_->in());
1040 return VisitStmt(stmt->getSubStmt(), in);
1041 }
1042
1043 DECL_VISIT_STMT(ReturnStmt) {
1044 VisitExpr(stmt->getRetValue(), env);
1045 return Environment::Unreachable();
299 } 1046 }
300 1047
301 const clang::TagType* ToTagType(const clang::Type* t) { 1048 const clang::TagType* ToTagType(const clang::Type* t) {
302 if (t == NULL) { 1049 if (t == NULL) {
303 return NULL; 1050 return NULL;
304 } else if (isa<clang::TagType>(t)) { 1051 } else if (isa<clang::TagType>(t)) {
305 return cast<clang::TagType>(t); 1052 return cast<clang::TagType>(t);
306 } else if (isa<clang::SubstTemplateTypeParmType>(t)) { 1053 } else if (isa<clang::SubstTemplateTypeParmType>(t)) {
307 return ToTagType(cast<clang::SubstTemplateTypeParmType>(t)-> 1054 return ToTagType(cast<clang::SubstTemplateTypeParmType>(t)->
308 getReplacementType().getTypePtr()); 1055 getReplacementType().getTypePtr());
309 } else { 1056 } else {
310 return NULL; 1057 return NULL;
311 } 1058 }
312 } 1059 }
313 1060
314 bool IsRawPointerType(clang::Expr* expr) { 1061 bool IsDerivedFrom(clang::CXXRecordDecl* record,
315 clang::QualType result = expr->getType(); 1062 clang::CXXRecordDecl* base) {
1063 return (record == base) || record->isDerivedFrom(base);
1064 }
316 1065
1066 bool IsRawPointerType(clang::QualType qtype) {
317 const clang::PointerType* type = 1067 const clang::PointerType* type =
318 dyn_cast_or_null<clang::PointerType>(expr->getType().getTypePtr()); 1068 dyn_cast_or_null<clang::PointerType>(qtype.getTypePtrOrNull());
319 if (type == NULL) return false; 1069 if (type == NULL) return false;
320 1070
321 const clang::TagType* pointee = 1071 const clang::TagType* pointee =
322 ToTagType(type->getPointeeType().getTypePtr()); 1072 ToTagType(type->getPointeeType().getTypePtr());
323 if (pointee == NULL) return false; 1073 if (pointee == NULL) return false;
324 1074
325 clang::CXXRecordDecl* record = 1075 clang::CXXRecordDecl* record =
326 dyn_cast_or_null<clang::CXXRecordDecl>(pointee->getDecl()); 1076 dyn_cast_or_null<clang::CXXRecordDecl>(pointee->getDecl());
327 if (record == NULL) return false; 1077 if (record == NULL) return false;
328 1078
329 return InV8Namespace(record) && 1079 if (!InV8Namespace(record)) return false;
330 record->hasDefinition() && 1080
331 ((record == objectDecl_) || record->isDerivedFrom(objectDecl_)); 1081 if (!record->hasDefinition()) return false;
1082
1083 record = record->getDefinition();
1084
1085 return IsDerivedFrom(record, objectDecl_) &&
1086 !IsDerivedFrom(record, smiDecl_);
332 } 1087 }
333 1088
334 bool IsHandleDereference(clang::Expr* expr) { 1089 Environment VisitDecl(clang::Decl* decl, const Environment& env) {
335 if (expr == NULL) { 1090 if (clang::VarDecl* var = dyn_cast<clang::VarDecl>(decl)) {
336 return false; 1091 Environment out = var->hasInit() ? VisitStmt(var->getInit(), env) : env;
337 } else if (isa<clang::UnaryOperator>(expr)) { 1092
338 clang::UnaryOperator* unop = cast<clang::UnaryOperator>(expr); 1093 if (IsRawPointerType(var->getType())) {
339 return unop->getOpcode() == clang::UO_Deref && 1094 out = out.Define(var->getNameAsString());
340 IsHandleType(handleDeclName_, unop->getSubExpr()->getType()); 1095 }
341 } else if (isa<clang::CXXOperatorCallExpr>(expr)) { 1096
342 clang::CXXOperatorCallExpr* op = cast<clang::CXXOperatorCallExpr>(expr); 1097 return out;
343 return (op->getOperator() == clang::OO_Star || 1098 }
344 op->getOperator() == clang::OO_Arrow) && 1099 // TODO: handle other declarations?
345 IsHandleType(handleDeclName_, op->getArg(0)->getType()); 1100 return env;
346 } else { 1101 }
347 return false; 1102
1103 DECL_VISIT_STMT(DeclStmt) {
1104 Environment out = env;
1105 for (clang::DeclStmt::decl_iterator decl = stmt->decl_begin(),
1106 end = stmt->decl_end();
1107 decl != end;
1108 ++decl) {
1109 out = VisitDecl(*decl, out);
1110 }
1111 return out;
1112 }
1113
1114
1115 void DefineParameters(const clang::FunctionDecl* f,
1116 Environment* env) {
1117 env->MDefine(THIS);
1118 for (clang::FunctionDecl::param_const_iterator p = f->param_begin(),
1119 end = f->param_end();
1120 p != end;
1121 ++p) {
1122 env->MDefine((*p)->getNameAsString());
348 } 1123 }
349 } 1124 }
350 1125
351 bool CanCauseGC(clang::Expr* expr) {
352 if (expr == NULL) return false;
353 1126
354 has_gc_ = false; 1127 void AnalyzeFunction(const clang::FunctionDecl* f) {
355 has_derefs_ = true; 1128 const clang::FunctionDecl* body = NULL;
356 TraverseStmt(expr); 1129 if (f->hasBody(body)) {
357 return has_gc_; 1130 Environment env;
1131 DefineParameters(body, &env);
1132 VisitStmt(body->getBody(), env);
1133 Environment::ClearSymbolTable();
1134 }
358 } 1135 }
359 1136
360 bool ManipulatesRawPointers(clang::Expr* expr) { 1137 Block* EnterBlock(Block* block) {
361 if (expr == NULL) return false; 1138 Block* parent = block_;
362 1139 block_ = block;
363 has_gc_ = true; 1140 return parent;
364 has_derefs_ = false;
365 TraverseStmt(expr);
366 return has_derefs_;
367 } 1141 }
368 1142
369 bool CanCauseGC(const clang::CallExpr* call) { 1143 void LeaveBlock(Block* block) {
370 const clang::FunctionDecl* fn = call->getDirectCallee(); 1144 block_ = block;
371 return (fn != NULL) && KnownToCauseGC(ctx_, fn);
372 } 1145 }
373 1146
374 // For generic expression classification. 1147 private:
375 bool has_derefs_; 1148 void ReportUnsafe(const clang::Expr* expr, const std::string& msg) {
376 bool has_gc_; 1149 d_.Report(clang::FullSourceLoc(expr->getExprLoc(), sm_),
1150 d_.getCustomDiagID(clang::Diagnostic::Warning, msg));
1151 }
377 1152
378 // For callsite classification.
379 static const int kMaxNumberOfArguments = 64;
380 std::bitset<kMaxNumberOfArguments> derefs_;
381 std::bitset<kMaxNumberOfArguments> gc_;
382 1153
1154 clang::MangleContext* ctx_;
383 clang::DeclarationName handleDeclName_; 1155 clang::DeclarationName handleDeclName_;
384 clang::MangleContext* ctx_;
385 clang::CXXRecordDecl* objectDecl_; 1156 clang::CXXRecordDecl* objectDecl_;
1157 clang::CXXRecordDecl* smiDecl_;
1158
1159 clang::Diagnostic& d_;
1160 clang::SourceManager& sm_;
1161
1162 Block* block_;
1163 bool dead_vars_analysis_;
386 }; 1164 };
387 1165
388 const std::string BAD_EXPRESSION_MSG("Possible problem with evaluation order.");
389 1166
390 class ExpressionsFinder : public clang::ASTConsumer, 1167 class ProblemsFinder : public clang::ASTConsumer,
391 public clang::RecursiveASTVisitor<ExpressionsFinder> { 1168 public clang::RecursiveASTVisitor<ProblemsFinder> {
392 public: 1169 public:
393 explicit ExpressionsFinder(clang::Diagnostic& d, clang::SourceManager& sm) 1170 ProblemsFinder(clang::Diagnostic& d,
394 : d_(d), sm_(sm) { } 1171 clang::SourceManager& sm,
395 1172 const std::vector<std::string>& args)
396 struct Resolver { 1173 : d_(d), sm_(sm), dead_vars_analysis_(false) {
397 explicit Resolver(clang::ASTContext& ctx) 1174 for (unsigned i = 0; i < args.size(); ++i) {
398 : ctx_(ctx), decl_ctx_(ctx.getTranslationUnitDecl()) { 1175 if (args[i] == "--dead-vars") {
1176 dead_vars_analysis_ = true;
1177 }
399 } 1178 }
400 1179 }
401 Resolver(clang::ASTContext& ctx, clang::DeclContext* decl_ctx)
402 : ctx_(ctx), decl_ctx_(decl_ctx) {
403 }
404
405 clang::DeclarationName ResolveName(const char* n) {
406 clang::IdentifierInfo* ident = &ctx_.Idents.get(n);
407 return ctx_.DeclarationNames.getIdentifier(ident);
408 }
409
410 Resolver ResolveNamespace(const char* n) {
411 return Resolver(ctx_, Resolve<clang::NamespaceDecl>(n));
412 }
413
414 template<typename T>
415 T* Resolve(const char* n) {
416 if (decl_ctx_ == NULL) return NULL;
417
418 clang::DeclContext::lookup_result result =
419 decl_ctx_->lookup(ResolveName(n));
420
421 for (clang::DeclContext::lookup_iterator i = result.first,
422 e = result.second;
423 i != e;
424 i++) {
425 if (isa<T>(*i)) return cast<T>(*i);
426 }
427
428 return NULL;
429 }
430
431 private:
432 clang::ASTContext& ctx_;
433 clang::DeclContext* decl_ctx_;
434 };
435 1180
436 virtual void HandleTranslationUnit(clang::ASTContext &ctx) { 1181 virtual void HandleTranslationUnit(clang::ASTContext &ctx) {
437 Resolver r(ctx); 1182 Resolver r(ctx);
438 1183
439 clang::CXXRecordDecl* objectDecl = 1184 clang::CXXRecordDecl* objectDecl =
440 r.ResolveNamespace("v8").ResolveNamespace("internal"). 1185 r.ResolveNamespace("v8").ResolveNamespace("internal").
441 Resolve<clang::CXXRecordDecl>("Object"); 1186 Resolve<clang::CXXRecordDecl>("Object");
442 1187
443 if (objectDecl != NULL) { 1188 clang::CXXRecordDecl* smiDecl =
Mads Ager (chromium) 2011/05/16 06:10:27 Why the switch in naming conventions? smi_decl and
444 expression_classifier_ = 1189 r.ResolveNamespace("v8").ResolveNamespace("internal").
445 new ExpressionClassifier(r.ResolveName("Handle"), 1190 Resolve<clang::CXXRecordDecl>("Smi");
446 clang::createItaniumMangleContext(ctx, d_), 1191
447 objectDecl); 1192 if (objectDecl != NULL) objectDecl = objectDecl->getDefinition();
1193
1194 if (smiDecl != NULL) smiDecl = smiDecl->getDefinition();
1195
1196 if (objectDecl != NULL && smiDecl != NULL) {
1197 function_analyzer_ =
1198 new FunctionAnalyzer(clang::createItaniumMangleContext(ctx, d_),
1199 r.ResolveName("Handle"),
1200 objectDecl,
1201 smiDecl,
1202 d_,
1203 sm_,
1204 dead_vars_analysis_);
448 TraverseDecl(ctx.getTranslationUnitDecl()); 1205 TraverseDecl(ctx.getTranslationUnitDecl());
449 } else { 1206 } else {
450 std::cerr << "Failed to resolve v8::internal::Object" << std::endl; 1207 if (objectDecl == NULL) {
1208 std::cerr << "Failed to resolve v8::internal::Object" << std::endl;
1209 }
1210 if (smiDecl == NULL) {
1211 std::cerr << "Failed to resolve v8::internal::Smi" << std::endl;
1212 }
451 } 1213 }
452 } 1214 }
453 1215
454 virtual bool VisitExpr(clang::Expr* expr) { 1216 virtual bool VisitFunctionDecl(clang::FunctionDecl* decl) {
455 if ( expression_classifier_->IsBadCallSite(expr) ) { 1217 function_analyzer_->AnalyzeFunction(decl);
456 d_.Report(clang::FullSourceLoc(expr->getExprLoc(), sm_),
457 d_.getCustomDiagID(clang::Diagnostic::Warning,
458 BAD_EXPRESSION_MSG));
459 }
460
461 return true; 1218 return true;
462 } 1219 }
463 1220
464 private: 1221 private:
465 clang::Diagnostic& d_; 1222 clang::Diagnostic& d_;
466 clang::SourceManager& sm_; 1223 clang::SourceManager& sm_;
1224 bool dead_vars_analysis_;
467 1225
468 ExpressionClassifier* expression_classifier_; 1226 FunctionAnalyzer* function_analyzer_;
469 }; 1227 };
470 1228
471 1229
472 template<typename ConsumerType> 1230 template<typename ConsumerType>
473 class Action : public clang::PluginASTAction { 1231 class Action : public clang::PluginASTAction {
474 protected: 1232 protected:
475 clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &CI, 1233 clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &CI,
476 llvm::StringRef InFile) { 1234 llvm::StringRef InFile) {
477 return new ConsumerType(CI.getDiagnostics(), CI.getSourceManager()); 1235 return new ConsumerType(CI.getDiagnostics(), CI.getSourceManager(), args_);
478 } 1236 }
479 1237
480 bool ParseArgs(const clang::CompilerInstance &CI, 1238 bool ParseArgs(const clang::CompilerInstance &CI,
481 const std::vector<std::string>& args) { 1239 const std::vector<std::string>& args) {
1240 args_ = args;
482 return true; 1241 return true;
483 } 1242 }
484 1243
485 void PrintHelp(llvm::raw_ostream& ros) { } 1244 void PrintHelp(llvm::raw_ostream& ros) {
1245 }
1246 private:
1247 std::vector<std::string> args_;
486 }; 1248 };
487 1249
488 1250
489 } 1251 }
490 1252
491 static clang::FrontendPluginRegistry::Add<Action<ExpressionsFinder> > 1253 static clang::FrontendPluginRegistry::Add<Action<ProblemsFinder> >
492 FindProblems("find-problems", "Find possible problems with evaluations order."); 1254 FindProblems("find-problems", "Find GC-unsafe places.");
493 1255
494 static clang::FrontendPluginRegistry::Add<Action<FunctionDeclarationFinder> > 1256 static clang::FrontendPluginRegistry::Add<
1257 Action<FunctionDeclarationFinder> >
495 DumpCallees("dump-callees", "Dump callees for each function."); 1258 DumpCallees("dump-callees", "Dump callees for each function.");
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698