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

Side by Side Diff: tools/clang/plugins/ChromeClassTester.cpp

Issue 520283002: . Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: notjustcalls Created 6 years, 3 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
« no previous file with comments | « tools/clang/plugins/ChromeClassTester.h ('k') | tools/clang/plugins/tests/base_passed.cpp » ('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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 // A general interface for filtering and only acting on classes in Chromium C++ 5 // A general interface for filtering and only acting on classes in Chromium C++
6 // code. 6 // code.
7 7
8 #include "ChromeClassTester.h" 8 #include "ChromeClassTester.h"
9 9
10 #include <sys/param.h> 10 #include <sys/param.h>
11 11
12 #include "clang/AST/AST.h" 12 #include "clang/AST/AST.h"
13 #include "clang/AST/Expr.h"
14 #include "clang/AST/RecursiveASTVisitor.h"
13 #include "clang/Basic/FileManager.h" 15 #include "clang/Basic/FileManager.h"
14 #include "clang/Basic/SourceManager.h" 16 #include "clang/Basic/SourceManager.h"
15 17
16 using namespace clang; 18 using namespace clang;
17 19
18 namespace { 20 namespace {
19 21
22 class FunctionVisitor : public RecursiveASTVisitor<FunctionVisitor> {
23 public:
24
25 bool shouldVisitTemplateInstantiations() { return true; }
26
27 bool VisitFunctionDecl(FunctionDecl* fun) {
28 if (fun->doesThisDeclarationHaveABody())
29 funcs_.push_back(fun);
30 return true;
31 }
32
33 std::vector<FunctionDecl*> funcs_;
34 };
35
36 bool isBasePassedCall(const CallExpr* CE, DeclRefExpr*& DREOut) {
37 const FunctionDecl* D = CE->getDirectCallee();
38 if (!D) return false;
39
40 const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext());
41 if (!ND) return false;
42 if (ND->getName() != "base") return false;
43 if (ND->getDeclContext()->getDeclKind() != Decl::TranslationUnit)
44 return false;
45
46 //auto FD = dyn_cast<FunctionDecl>(D);
47 if (!D->getIdentifier()) return false;
48 if (D->getName() != "Passed") return false;
49 if (D->getNumParams() != 1) return false;
50
51 const Expr *Arg = CE->getArg(0)->IgnoreParenImpCasts();
52 DeclRefExpr* DRE = nullptr;
53 if (const UnaryOperator* Op = dyn_cast<UnaryOperator>(Arg)) {
54 // This branch is for base::Passed(&s)
55 if (Op->getOpcode() == UO_AddrOf)
56 DRE = dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts());
57 } else {
58 // This branch is for base::Passed(s.Pass())
59 // Look through:
60 // CXXBindTemporaryExpr
61 // CXXConstructExpr
62 // `-CXXConstructExpr
63 // `-MaterializeTemporaryExpr
64 // `-ImplicitCastExpr
65 // `-ImplicitCastExpr
66 // `-CXXMemberCallExpr scoped_ptr<int>::RValue
67 // `-MemberExpr 0x104080510 .operator RValue
68 // `-CXXMemberCallExpr base::scoped_ptr<int>
69 // `-MemberExpr .Pass
70 // `-DeclRefExpr base::scoped_ptr<int>
71 if (const CXXBindTemporaryExpr *TE = dyn_cast<CXXBindTemporaryExpr>(Arg))
72 Arg = TE->getSubExpr();
73 while (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Arg)) {
74 if (CE->getNumArgs() != 1)
75 return false;
76 Arg = CE->getArg(0)->IgnoreParenImpCasts();
77 }
78 while (const CXXMemberCallExpr* MC = dyn_cast<CXXMemberCallExpr>(Arg)) {
79 CXXMethodDecl *MD = MC->getMethodDecl();
80 if (MD->getIdentifier() && MD->getName() == "Pass") {
81 DRE = dyn_cast<DeclRefExpr>(
82 MC->getImplicitObjectArgument()->IgnoreParenImpCasts());
83 break;
84 }
85 Arg = cast<MemberExpr>(MC->getCallee())->getBase()->IgnoreParenImpCasts();
86 if (const CXXBindTemporaryExpr *TE = dyn_cast<CXXBindTemporaryExpr>(Arg))
87 Arg = TE->getSubExpr();
88 }
89 }
90
91 if (!DRE) return false; // FIXME: or complain? What would this be?
92
93 DREOut = DRE;
94 return true;
95 }
96
97 typedef std::map<const Decl*, DeclRefExpr*> UseMap;
98
99 // |Expr| is a Stmt due to StmtExprs.
100 void AddAll(std::vector<const DeclRefExpr*>* out, UseMap* m, Stmt* SExpr) {
101 if (auto CE = dyn_cast<CallExpr>(SExpr)) {
102 // Don't push the DRE from within a base::Passed() CallExpr!
103 DeclRefExpr* DRE;
104 if (isBasePassedCall(CE, DRE)) {
105 (*m)[DRE->getDecl()] = DRE;
106 return;
107 }
108 // FIXME: What if it's a base::Passed() call taking something weird?
109 }
110 else if (auto DRE = dyn_cast<DeclRefExpr>(SExpr))
111 out->push_back(DRE);
112
113 for (Stmt* C : SExpr->children()) {
114 if (!C) continue;
115 AddAll(out, m, C);
116 }
117 }
118
119 void CheckExpr(ChromeClassTester& CCT, Expr* S, ASTContext& ctx) {
120 // Recursively collect all expressions in arguments
121 // (this has some false positives, as it stuffs things like "a ? b : c" into
122 // the flat vector even though that has a sequence point).
123 std::vector<const DeclRefExpr*> ArgExprs;
124 UseMap uses;
125 AddAll(&ArgExprs, &uses, S);
126
127 // Find all declrefexprs that are both:
128 // 1.) Passed to base::Passed() (which invalidates them)
129 // 2.) Used in some other way (e.g. have their .get() called)
130
131 for (const DeclRefExpr* E : ArgExprs) {
132 auto it = uses.find(E->getDecl());
133 if (it != uses.end()) {
134 CCT.diagnostic().Report(E->getLocation(),
135 CCT.diag_might_be_gone_);
136 CCT.diagnostic().Report(it->second->getLocation(),
137 CCT.diag_might_be_gone_note_here_);
138 }
139 }
140 }
141
142 void CheckStmts(ChromeClassTester& CCT, Stmt* S, ASTContext& ctx) {
143 for (auto* C : S->children()) {
144 if (!C) continue;
145
146 if (auto* Call = dyn_cast<Expr>(C))
147 CheckExpr(CCT, Call, ctx);
148 else
149 CheckStmts(CCT, C, ctx);
150 }
151 }
152
20 bool starts_with(const std::string& one, const std::string& two) { 153 bool starts_with(const std::string& one, const std::string& two) {
21 return one.compare(0, two.size(), two) == 0; 154 return one.compare(0, two.size(), two) == 0;
22 } 155 }
23 156
24 std::string lstrip(const std::string& one, const std::string& two) { 157 std::string lstrip(const std::string& one, const std::string& two) {
25 if (starts_with(one, two)) 158 if (starts_with(one, two))
26 return one.substr(two.size()); 159 return one.substr(two.size());
27 return one; 160 return one;
28 } 161 }
29 162
30 bool ends_with(const std::string& one, const std::string& two) { 163 bool ends_with(const std::string& one, const std::string& two) {
31 if (two.size() > one.size()) 164 if (two.size() > one.size())
32 return false; 165 return false;
33 166
34 return one.compare(one.size() - two.size(), two.size(), two) == 0; 167 return one.compare(one.size() - two.size(), two.size(), two) == 0;
35 } 168 }
36 169
37 } // namespace 170 } // namespace
38 171
39 ChromeClassTester::ChromeClassTester(CompilerInstance& instance) 172 ChromeClassTester::ChromeClassTester(CompilerInstance& instance)
40 : instance_(instance), 173 : instance_(instance),
41 diagnostic_(instance.getDiagnostics()) { 174 diagnostic_(instance.getDiagnostics()) {
175
176 diag_might_be_gone_ =
177 diagnostic().getCustomDiagID(DiagnosticsEngine::Warning,
178 "reference might be destroyed here");
179 diag_might_be_gone_note_here_ =
180 diagnostic().getCustomDiagID(DiagnosticsEngine::Note,
181 "invalidated here");
42 BuildBannedLists(); 182 BuildBannedLists();
43 } 183 }
44 184
45 ChromeClassTester::~ChromeClassTester() {} 185 ChromeClassTester::~ChromeClassTester() {}
46 186
47 void ChromeClassTester::HandleTagDeclDefinition(TagDecl* tag) { 187 void ChromeClassTester::HandleTagDeclDefinition(TagDecl* tag) {
48 pending_class_decls_.push_back(tag); 188 pending_class_decls_.push_back(tag);
49 } 189 }
50 190
51 bool ChromeClassTester::HandleTopLevelDecl(DeclGroupRef group_ref) { 191 bool ChromeClassTester::HandleTopLevelDecl(DeclGroupRef group_ref) {
52 for (size_t i = 0; i < pending_class_decls_.size(); ++i) 192 for (size_t i = 0; i < pending_class_decls_.size(); ++i)
53 CheckTag(pending_class_decls_[i]); 193 CheckTag(pending_class_decls_[i]);
54 pending_class_decls_.clear(); 194 pending_class_decls_.clear();
55 195
56 return true; // true means continue parsing. 196 return true; // true means continue parsing.
57 } 197 }
58 198
199 void ChromeClassTester::HandleTranslationUnit(ASTContext& Context) {
200 FunctionVisitor visitor;
201 visitor.TraverseDecl(Context.getTranslationUnitDecl());
202
203 // Now all function decls are in visitor.funcs_.
204 for (auto* Fun : visitor.funcs_) {
205 Stmt* Body = Fun->getBody();
206 assert(Body && "Only definitions should be passed here");
207 CheckStmts(*this, Body, Context);
208 }
209 }
210
59 void ChromeClassTester::CheckTag(TagDecl* tag) { 211 void ChromeClassTester::CheckTag(TagDecl* tag) {
60 // We handle class types here where we have semantic information. We can only 212 // We handle class types here where we have semantic information. We can only
61 // check structs/classes/enums here, but we get a bunch of nice semantic 213 // check structs/classes/enums here, but we get a bunch of nice semantic
62 // information instead of just parsing information. 214 // information instead of just parsing information.
63 215
64 if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) { 216 if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) {
65 // If this is a POD or a class template or a type dependent on a 217 // If this is a POD or a class template or a type dependent on a
66 // templated class, assume there's no ctor/dtor/virtual method 218 // templated class, assume there's no ctor/dtor/virtual method
67 // optimization that we can do. 219 // optimization that we can do.
68 if (record->isPOD() || 220 if (record->isPOD() ||
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 PresumedLoc ploc = source_manager.getPresumedLoc(spelling_location); 460 PresumedLoc ploc = source_manager.getPresumedLoc(spelling_location);
309 if (ploc.isInvalid()) { 461 if (ploc.isInvalid()) {
310 // If we're in an invalid location, we're looking at things that aren't 462 // If we're in an invalid location, we're looking at things that aren't
311 // actually stated in the source. 463 // actually stated in the source.
312 return false; 464 return false;
313 } 465 }
314 466
315 *filename = ploc.getFilename(); 467 *filename = ploc.getFilename();
316 return true; 468 return true;
317 } 469 }
OLDNEW
« no previous file with comments | « tools/clang/plugins/ChromeClassTester.h ('k') | tools/clang/plugins/tests/base_passed.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698