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

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

Issue 520283002: . Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . 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
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 // FIXME: Require this &? Or is without something to catch too?
52 const UnaryOperator* Op =
53 dyn_cast<UnaryOperator>(CE->getArg(0)->IgnoreParenImpCasts());
54 if (!Op || Op->getOpcode() != UO_AddrOf) return false;
55
56 DeclRefExpr* DRE =
57 dyn_cast<DeclRefExpr>(Op->getSubExpr()->IgnoreParenImpCasts());
58 if (!DRE) return false; // FIXME: or complain? What would this be?
59
60 DREOut = DRE;
61 return true;
62 }
63
64 typedef std::map<const Decl*, DeclRefExpr*> UseMap;
65
66 // |Expr| is a Stmt due to StmtExprs.
67 void AddAll(std::vector<const DeclRefExpr*>* out, UseMap* m, Stmt* SExpr) {
68 if (auto CE = dyn_cast<CallExpr>(SExpr)) {
69 // Don't push the DRE from within a base::Passed() CallExpr!
70 DeclRefExpr* DRE;
71 if (isBasePassedCall(CE, DRE)) {
72 (*m)[DRE->getDecl()] = DRE;
73 return;
74 }
75 // FIXME: What if it's a base::Passed() call taking something weird?
76 }
77 else if (auto DRE = dyn_cast<DeclRefExpr>(SExpr))
78 out->push_back(DRE);
79
80 for (Stmt* C : SExpr->children()) {
81 if (!C) continue;
82 AddAll(out, m, C);
83 }
84 }
85
86 void CheckCall(ChromeClassTester& CCT, CallExpr* S, ASTContext& ctx) {
87 // Recursively collect all expressions in arguments
88 // (this has some false positives, as it stuffs things like "a ? b : c" into
89 // the flat vector even though that has a sequence point).
90 std::vector<const DeclRefExpr*> ArgExprs;
91 UseMap uses;
92 AddAll(&ArgExprs, &uses, S);
93
94 // Find all declrefexprs that are both:
95 // 1.) Passed to base::Passed() (which invalidates them)
96 // 2.) Used in some other way (e.g. have their .get() called)
97
98 for (const DeclRefExpr* E : ArgExprs) {
99 auto it = uses.find(E->getDecl());
100 if (it != uses.end()) {
101 CCT.diagnostic().Report(E->getLocation(),
102 CCT.diag_might_be_gone_);
103 CCT.diagnostic().Report(it->second->getLocation(),
104 CCT.diag_might_be_gone_note_here_);
105 }
106 }
107 }
108
109 void CheckStmts(ChromeClassTester& CCT, Stmt* S, ASTContext& ctx) {
110 for (auto* C : S->children()) {
111 if (!C) continue;
112
113 if (auto* Call = dyn_cast<CallExpr>(C))
114 CheckCall(CCT, Call, ctx);
115 else
116 CheckStmts(CCT, C, ctx);
117 }
118 }
119
20 bool starts_with(const std::string& one, const std::string& two) { 120 bool starts_with(const std::string& one, const std::string& two) {
21 return one.compare(0, two.size(), two) == 0; 121 return one.compare(0, two.size(), two) == 0;
22 } 122 }
23 123
24 std::string lstrip(const std::string& one, const std::string& two) { 124 std::string lstrip(const std::string& one, const std::string& two) {
25 if (starts_with(one, two)) 125 if (starts_with(one, two))
26 return one.substr(two.size()); 126 return one.substr(two.size());
27 return one; 127 return one;
28 } 128 }
29 129
30 bool ends_with(const std::string& one, const std::string& two) { 130 bool ends_with(const std::string& one, const std::string& two) {
31 if (two.size() > one.size()) 131 if (two.size() > one.size())
32 return false; 132 return false;
33 133
34 return one.compare(one.size() - two.size(), two.size(), two) == 0; 134 return one.compare(one.size() - two.size(), two.size(), two) == 0;
35 } 135 }
36 136
37 } // namespace 137 } // namespace
38 138
39 ChromeClassTester::ChromeClassTester(CompilerInstance& instance) 139 ChromeClassTester::ChromeClassTester(CompilerInstance& instance)
40 : instance_(instance), 140 : instance_(instance),
41 diagnostic_(instance.getDiagnostics()) { 141 diagnostic_(instance.getDiagnostics()) {
142
143 diag_might_be_gone_ =
144 diagnostic().getCustomDiagID(DiagnosticsEngine::Warning,
145 "reference might be destroyed here");
146 diag_might_be_gone_note_here_ =
147 diagnostic().getCustomDiagID(DiagnosticsEngine::Note,
148 "invalidated here");
42 BuildBannedLists(); 149 BuildBannedLists();
43 } 150 }
44 151
45 ChromeClassTester::~ChromeClassTester() {} 152 ChromeClassTester::~ChromeClassTester() {}
46 153
47 void ChromeClassTester::HandleTagDeclDefinition(TagDecl* tag) { 154 void ChromeClassTester::HandleTagDeclDefinition(TagDecl* tag) {
48 pending_class_decls_.push_back(tag); 155 pending_class_decls_.push_back(tag);
49 } 156 }
50 157
51 bool ChromeClassTester::HandleTopLevelDecl(DeclGroupRef group_ref) { 158 bool ChromeClassTester::HandleTopLevelDecl(DeclGroupRef group_ref) {
52 for (size_t i = 0; i < pending_class_decls_.size(); ++i) 159 for (size_t i = 0; i < pending_class_decls_.size(); ++i)
53 CheckTag(pending_class_decls_[i]); 160 CheckTag(pending_class_decls_[i]);
54 pending_class_decls_.clear(); 161 pending_class_decls_.clear();
55 162
56 return true; // true means continue parsing. 163 return true; // true means continue parsing.
57 } 164 }
58 165
166 void ChromeClassTester::HandleTranslationUnit(ASTContext& Context) {
167 FunctionVisitor visitor;
168 visitor.TraverseDecl(Context.getTranslationUnitDecl());
169
170 // Now all function decls are in visitor.funcs_.
171 for (auto* Fun : visitor.funcs_) {
172 Stmt* Body = Fun->getBody();
173 assert(Body && "Only definitions should be passed here");
174 CheckStmts(*this, Body, Context);
175 }
176 }
177
59 void ChromeClassTester::CheckTag(TagDecl* tag) { 178 void ChromeClassTester::CheckTag(TagDecl* tag) {
60 // We handle class types here where we have semantic information. We can only 179 // 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 180 // check structs/classes/enums here, but we get a bunch of nice semantic
62 // information instead of just parsing information. 181 // information instead of just parsing information.
63 182
64 if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) { 183 if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) {
65 // If this is a POD or a class template or a type dependent on a 184 // 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 185 // templated class, assume there's no ctor/dtor/virtual method
67 // optimization that we can do. 186 // optimization that we can do.
68 if (record->isPOD() || 187 if (record->isPOD() ||
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 PresumedLoc ploc = source_manager.getPresumedLoc(spelling_location); 427 PresumedLoc ploc = source_manager.getPresumedLoc(spelling_location);
309 if (ploc.isInvalid()) { 428 if (ploc.isInvalid()) {
310 // If we're in an invalid location, we're looking at things that aren't 429 // If we're in an invalid location, we're looking at things that aren't
311 // actually stated in the source. 430 // actually stated in the source.
312 return false; 431 return false;
313 } 432 }
314 433
315 *filename = ploc.getFilename(); 434 *filename = ploc.getFilename();
316 return true; 435 return true;
317 } 436 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698