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
3 // found in the LICENSE file.
4 
5 #include "FindBadConstructsConsumer.h"
6 
7 #include "Util.h"
8 #include "clang/AST/Attr.h"
9 #include "clang/Frontend/CompilerInstance.h"
10 #include "clang/Lex/Lexer.h"
11 #include "clang/Sema/Sema.h"
12 #include "llvm/Support/raw_ostream.h"
13 
14 using namespace clang;
15 
16 namespace chrome_checker {
17 
18 namespace {
19 
20 // Returns the underlying Type for |type| by expanding typedefs and removing
21 // any namespace qualifiers. This is similar to desugaring, except that for
22 // ElaboratedTypes, desugar will unwrap too much.
UnwrapType(const Type * type)23 const Type* UnwrapType(const Type* type) {
24   if (const ElaboratedType* elaborated = dyn_cast<ElaboratedType>(type))
25     return UnwrapType(elaborated->getNamedType().getTypePtr());
26   if (const TypedefType* typedefed = dyn_cast<TypedefType>(type))
27     return UnwrapType(typedefed->desugar().getTypePtr());
28   return type;
29 }
30 
InTestingNamespace(const Decl * record)31 bool InTestingNamespace(const Decl* record) {
32   return GetNamespace(record).find("testing") != std::string::npos;
33 }
34 
IsGtestTestFixture(const CXXRecordDecl * decl)35 bool IsGtestTestFixture(const CXXRecordDecl* decl) {
36   return decl->getQualifiedNameAsString() == "testing::Test";
37 }
38 
IsMethodInTestingNamespace(const CXXMethodDecl * method)39 bool IsMethodInTestingNamespace(const CXXMethodDecl* method) {
40   for (auto* overridden : method->overridden_methods()) {
41     if (IsMethodInTestingNamespace(overridden) ||
42         // Provide an exception for ::testing::Test. gtest itself uses some
43         // magic to try to make sure SetUp()/TearDown() aren't capitalized
44         // incorrectly, but having the plugin enforce override is also nice.
45         (InTestingNamespace(overridden) &&
46          !IsGtestTestFixture(overridden->getParent()))) {
47       return true;
48     }
49   }
50 
51   return false;
52 }
53 
IsGmockObject(const CXXRecordDecl * decl)54 bool IsGmockObject(const CXXRecordDecl* decl) {
55   // If |record| has member variables whose types are in the "testing" namespace
56   // (which is how gmock works behind the scenes), there's a really high chance
57   // that |record| is a gmock object.
58   for (auto* field : decl->fields()) {
59     CXXRecordDecl* record_type = field->getTypeSourceInfo()
60                                      ->getTypeLoc()
61                                      .getTypePtr()
62                                      ->getAsCXXRecordDecl();
63     if (record_type) {
64       if (InTestingNamespace(record_type)) {
65         return true;
66       }
67     }
68   }
69   return false;
70 }
71 
IsPodOrTemplateType(const CXXRecordDecl & record)72 bool IsPodOrTemplateType(const CXXRecordDecl& record) {
73   return record.isPOD() ||
74          record.getDescribedClassTemplate() ||
75          record.getTemplateSpecializationKind() ||
76          record.isDependentType();
77 }
78 
79 // Use a local RAV implementation to simply collect all FunctionDecls marked for
80 // late template parsing. This happens with the flag -fdelayed-template-parsing,
81 // which is on by default in MSVC-compatible mode.
GetLateParsedFunctionDecls(TranslationUnitDecl * decl)82 std::set<FunctionDecl*> GetLateParsedFunctionDecls(TranslationUnitDecl* decl) {
83   struct Visitor : public RecursiveASTVisitor<Visitor> {
84     bool VisitFunctionDecl(FunctionDecl* function_decl) {
85       if (function_decl->isLateTemplateParsed())
86         late_parsed_decls.insert(function_decl);
87       return true;
88     }
89 
90     std::set<FunctionDecl*> late_parsed_decls;
91   } v;
92   v.TraverseDecl(decl);
93   return v.late_parsed_decls;
94 }
95 
GetAutoReplacementTypeAsString(QualType type,StorageClass storage_class)96 std::string GetAutoReplacementTypeAsString(QualType type,
97                                            StorageClass storage_class) {
98   QualType non_reference_type = type.getNonReferenceType();
99   if (!non_reference_type->isPointerType())
100     return storage_class == SC_Static ? "static auto" : "auto";
101 
102   std::string result = GetAutoReplacementTypeAsString(
103       non_reference_type->getPointeeType(), storage_class);
104   result += "*";
105   if (non_reference_type.isConstQualified())
106     result += " const";
107   if (non_reference_type.isVolatileQualified())
108     result += " volatile";
109   if (type->isReferenceType() && !non_reference_type.isConstQualified()) {
110     if (type->isLValueReferenceType())
111       result += "&";
112     else if (type->isRValueReferenceType())
113       result += "&&";
114   }
115   return result;
116 }
117 
118 }  // namespace
119 
FindBadConstructsConsumer(CompilerInstance & instance,const Options & options)120 FindBadConstructsConsumer::FindBadConstructsConsumer(CompilerInstance& instance,
121                                                      const Options& options)
122     : ChromeClassTester(instance, options) {
123   if (options.check_ipc) {
124     ipc_visitor_.reset(new CheckIPCVisitor(instance));
125   }
126 
127   // Messages for virtual methods.
128   diag_method_requires_override_ = diagnostic().getCustomDiagID(
129       getErrorLevel(),
130       "[chromium-style] Overriding method must be marked with 'override' or "
131       "'final'.");
132   diag_redundant_virtual_specifier_ = diagnostic().getCustomDiagID(
133       getErrorLevel(), "[chromium-style] %0 is redundant; %1 implies %0.");
134   diag_will_be_redundant_virtual_specifier_ = diagnostic().getCustomDiagID(
135       getErrorLevel(), "[chromium-style] %0 will be redundant; %1 implies %0.");
136   // http://llvm.org/bugs/show_bug.cgi?id=21051 has been filed to make this a
137   // Clang warning.
138   diag_base_method_virtual_and_final_ = diagnostic().getCustomDiagID(
139       getErrorLevel(),
140       "[chromium-style] The virtual method does not override anything and is "
141       "final; consider making it non-virtual.");
142   diag_virtual_with_inline_body_ = diagnostic().getCustomDiagID(
143       getErrorLevel(),
144       "[chromium-style] virtual methods with non-empty bodies shouldn't be "
145       "declared inline.");
146 
147   // Messages for constructors.
148   diag_no_explicit_ctor_ = diagnostic().getCustomDiagID(
149       getErrorLevel(),
150       "[chromium-style] Complex class/struct needs an explicit out-of-line "
151       "constructor.");
152   diag_no_explicit_copy_ctor_ = diagnostic().getCustomDiagID(
153       getErrorLevel(),
154       "[chromium-style] Complex class/struct needs an explicit out-of-line "
155       "copy constructor.");
156   diag_inline_complex_ctor_ = diagnostic().getCustomDiagID(
157       getErrorLevel(),
158       "[chromium-style] Complex constructor has an inlined body.");
159 
160   // Messages for destructors.
161   diag_no_explicit_dtor_ = diagnostic().getCustomDiagID(
162       getErrorLevel(),
163       "[chromium-style] Complex class/struct needs an explicit out-of-line "
164       "destructor.");
165   diag_inline_complex_dtor_ = diagnostic().getCustomDiagID(
166       getErrorLevel(),
167       "[chromium-style] Complex destructor has an inline body.");
168 
169   // Messages for refcounted objects.
170   diag_refcounted_needs_explicit_dtor_ = diagnostic().getCustomDiagID(
171       getErrorLevel(),
172       "[chromium-style] Classes that are ref-counted should have explicit "
173       "destructors that are declared protected or private.");
174   diag_refcounted_with_public_dtor_ = diagnostic().getCustomDiagID(
175       getErrorLevel(),
176       "[chromium-style] Classes that are ref-counted should have "
177       "destructors that are declared protected or private.");
178   diag_refcounted_with_protected_non_virtual_dtor_ =
179       diagnostic().getCustomDiagID(
180           getErrorLevel(),
181           "[chromium-style] Classes that are ref-counted and have non-private "
182           "destructors should declare their destructor virtual.");
183 
184   // Miscellaneous messages.
185   diag_weak_ptr_factory_order_ = diagnostic().getCustomDiagID(
186       getErrorLevel(),
187       "[chromium-style] WeakPtrFactory members which refer to their outer "
188       "class must be the last member in the outer class definition.");
189   diag_bad_enum_max_value_ = diagnostic().getCustomDiagID(
190       getErrorLevel(),
191       "[chromium-style] kMaxValue enumerator does not match max value %0 of "
192       "other enumerators");
193   diag_enum_max_value_unique_ = diagnostic().getCustomDiagID(
194       getErrorLevel(),
195       "[chromium-style] kMaxValue enumerator should not have a unique value: "
196       "it should share the value of the highest enumerator");
197   diag_auto_deduced_to_a_pointer_type_ =
198       diagnostic().getCustomDiagID(getErrorLevel(),
199                                    "[chromium-style] auto variable type "
200                                    "must not deduce to a raw pointer "
201                                    "type.");
202 
203   // Registers notes to make it easier to interpret warnings.
204   diag_note_inheritance_ = diagnostic().getCustomDiagID(
205       DiagnosticsEngine::Note, "[chromium-style] %0 inherits from %1 here");
206   diag_note_implicit_dtor_ = diagnostic().getCustomDiagID(
207       DiagnosticsEngine::Note,
208       "[chromium-style] No explicit destructor for %0 defined");
209   diag_note_public_dtor_ = diagnostic().getCustomDiagID(
210       DiagnosticsEngine::Note,
211       "[chromium-style] Public destructor declared here");
212   diag_note_protected_non_virtual_dtor_ = diagnostic().getCustomDiagID(
213       DiagnosticsEngine::Note,
214       "[chromium-style] Protected non-virtual destructor declared here");
215 }
216 
Traverse(ASTContext & context)217 void FindBadConstructsConsumer::Traverse(ASTContext& context) {
218   if (ipc_visitor_) {
219     ipc_visitor_->set_context(&context);
220     ParseFunctionTemplates(context.getTranslationUnitDecl());
221   }
222   RecursiveASTVisitor::TraverseDecl(context.getTranslationUnitDecl());
223   if (ipc_visitor_) ipc_visitor_->set_context(nullptr);
224 }
225 
TraverseDecl(Decl * decl)226 bool FindBadConstructsConsumer::TraverseDecl(Decl* decl) {
227   if (ipc_visitor_) ipc_visitor_->BeginDecl(decl);
228   bool result = RecursiveASTVisitor::TraverseDecl(decl);
229   if (ipc_visitor_) ipc_visitor_->EndDecl();
230   return result;
231 }
232 
VisitEnumDecl(clang::EnumDecl * decl)233 bool FindBadConstructsConsumer::VisitEnumDecl(clang::EnumDecl* decl) {
234   CheckEnumMaxValue(decl);
235   return true;
236 }
237 
VisitTagDecl(clang::TagDecl * tag_decl)238 bool FindBadConstructsConsumer::VisitTagDecl(clang::TagDecl* tag_decl) {
239   if (tag_decl->isCompleteDefinition())
240     CheckTag(tag_decl);
241   return true;
242 }
243 
VisitTemplateSpecializationType(TemplateSpecializationType * spec)244 bool FindBadConstructsConsumer::VisitTemplateSpecializationType(
245     TemplateSpecializationType* spec) {
246   if (ipc_visitor_) ipc_visitor_->VisitTemplateSpecializationType(spec);
247   return true;
248 }
249 
VisitCallExpr(CallExpr * call_expr)250 bool FindBadConstructsConsumer::VisitCallExpr(CallExpr* call_expr) {
251   if (ipc_visitor_) ipc_visitor_->VisitCallExpr(call_expr);
252   return true;
253 }
254 
VisitVarDecl(clang::VarDecl * var_decl)255 bool FindBadConstructsConsumer::VisitVarDecl(clang::VarDecl* var_decl) {
256   CheckVarDecl(var_decl);
257   return true;
258 }
259 
CheckChromeClass(LocationType location_type,SourceLocation record_location,CXXRecordDecl * record)260 void FindBadConstructsConsumer::CheckChromeClass(LocationType location_type,
261                                                  SourceLocation record_location,
262                                                  CXXRecordDecl* record) {
263   bool implementation_file = InImplementationFile(record_location);
264 
265   if (!implementation_file) {
266     // Only check for "heavy" constructors/destructors in header files;
267     // within implementation files, there is no performance cost.
268 
269     // If this is a POD or a class template or a type dependent on a
270     // templated class, assume there's no ctor/dtor/virtual method
271     // optimization that we should do.
272     if (!IsPodOrTemplateType(*record))
273       CheckCtorDtorWeight(record_location, record);
274   }
275 
276   bool warn_on_inline_bodies = !implementation_file;
277   // Check that all virtual methods are annotated with override or final.
278   // Note this could also apply to templates, but for some reason Clang
279   // does not always see the "override", so we get false positives.
280   // See http://llvm.org/bugs/show_bug.cgi?id=18440 and
281   //     http://llvm.org/bugs/show_bug.cgi?id=21942
282   if (!IsPodOrTemplateType(*record))
283     CheckVirtualMethods(record_location, record, warn_on_inline_bodies);
284 
285   // TODO(dcheng): This is needed because some of the diagnostics for refcounted
286   // classes use DiagnosticsEngine::Report() directly, and there are existing
287   // violations in Blink. This should be removed once the checks are
288   // modularized.
289   if (location_type != LocationType::kBlink)
290     CheckRefCountedDtors(record_location, record);
291 
292   CheckWeakPtrFactoryMembers(record_location, record);
293 }
294 
CheckEnumMaxValue(EnumDecl * decl)295 void FindBadConstructsConsumer::CheckEnumMaxValue(EnumDecl* decl) {
296   if (!decl->isScoped())
297     return;
298 
299   clang::EnumConstantDecl* max_value = nullptr;
300   std::set<clang::EnumConstantDecl*> max_enumerators;
301   llvm::APSInt max_seen;
302   for (clang::EnumConstantDecl* enumerator : decl->enumerators()) {
303     if (enumerator->getName() == "kMaxValue")
304       max_value = enumerator;
305 
306     llvm::APSInt current_value = enumerator->getInitVal();
307     if (max_enumerators.empty()) {
308       max_enumerators.emplace(enumerator);
309       max_seen = current_value;
310       continue;
311     }
312 
313     assert(max_seen.isSigned() == current_value.isSigned());
314 
315     if (current_value < max_seen)
316       continue;
317 
318     if (current_value == max_seen) {
319       max_enumerators.emplace(enumerator);
320       continue;
321     }
322 
323     assert(current_value > max_seen);
324     max_enumerators.clear();
325     max_enumerators.emplace(enumerator);
326     max_seen = current_value;
327   }
328 
329   if (!max_value)
330     return;
331 
332   if (max_enumerators.find(max_value) == max_enumerators.end()) {
333     ReportIfSpellingLocNotIgnored(max_value->getLocation(),
334                                   diag_bad_enum_max_value_)
335         << max_seen.toString(10);
336   } else if (max_enumerators.size() < 2) {
337     ReportIfSpellingLocNotIgnored(decl->getLocation(),
338                                   diag_enum_max_value_unique_);
339   }
340 }
341 
CheckCtorDtorWeight(SourceLocation record_location,CXXRecordDecl * record)342 void FindBadConstructsConsumer::CheckCtorDtorWeight(
343     SourceLocation record_location,
344     CXXRecordDecl* record) {
345   // We don't handle anonymous structs. If this record doesn't have a
346   // name, it's of the form:
347   //
348   // struct {
349   //   ...
350   // } name_;
351   if (record->getIdentifier() == NULL)
352     return;
353 
354   // We don't handle unions.
355   if (record->isUnion())
356     return;
357 
358   // Skip records that derive from ignored base classes.
359   if (HasIgnoredBases(record))
360     return;
361 
362   // Count the number of templated base classes as a feature of whether the
363   // destructor can be inlined.
364   int templated_base_classes = 0;
365   for (CXXRecordDecl::base_class_const_iterator it = record->bases_begin();
366        it != record->bases_end();
367        ++it) {
368     if (it->getTypeSourceInfo()->getTypeLoc().getTypeLocClass() ==
369         TypeLoc::TemplateSpecialization) {
370       ++templated_base_classes;
371     }
372   }
373 
374   // Count the number of trivial and non-trivial member variables.
375   int trivial_member = 0;
376   int non_trivial_member = 0;
377   int templated_non_trivial_member = 0;
378   for (RecordDecl::field_iterator it = record->field_begin();
379        it != record->field_end();
380        ++it) {
381     CountType(it->getType().getTypePtr(),
382               &trivial_member,
383               &non_trivial_member,
384               &templated_non_trivial_member);
385   }
386 
387   // Check to see if we need to ban inlined/synthesized constructors. Note
388   // that the cutoffs here are kind of arbitrary. Scores over 10 break.
389   int dtor_score = 0;
390   // Deriving from a templated base class shouldn't be enough to trigger
391   // the ctor warning, but if you do *anything* else, it should.
392   //
393   // TODO(erg): This is motivated by templated base classes that don't have
394   // any data members. Somehow detect when templated base classes have data
395   // members and treat them differently.
396   dtor_score += templated_base_classes * 9;
397   // Instantiating a template is an insta-hit.
398   dtor_score += templated_non_trivial_member * 10;
399   // The fourth normal class member should trigger the warning.
400   dtor_score += non_trivial_member * 3;
401 
402   int ctor_score = dtor_score;
403   // You should be able to have 9 ints before we warn you.
404   ctor_score += trivial_member;
405 
406   if (ctor_score >= 10) {
407     if (!record->hasUserDeclaredConstructor()) {
408       ReportIfSpellingLocNotIgnored(record_location, diag_no_explicit_ctor_);
409     } else {
410       // Iterate across all the constructors in this file and yell if we
411       // find one that tries to be inline.
412       for (CXXRecordDecl::ctor_iterator it = record->ctor_begin();
413            it != record->ctor_end();
414            ++it) {
415         // The current check is buggy. An implicit copy constructor does not
416         // have an inline body, so this check never fires for classes with a
417         // user-declared out-of-line constructor.
418         if (it->hasInlineBody()) {
419           if (it->isCopyConstructor() &&
420               !record->hasUserDeclaredCopyConstructor()) {
421             // In general, implicit constructors are generated on demand.  But
422             // in the Windows component build, dllexport causes instantiation of
423             // the copy constructor which means that this fires on many more
424             // classes. For now, suppress this on dllexported classes.
425             // (This does mean that windows component builds will not emit this
426             // warning in some cases where it is emitted in other configs, but
427             // that's the better tradeoff at this point).
428             // TODO(dcheng): With the RecursiveASTVisitor, these warnings might
429             // be emitted on other platforms too, reevaluate if we want to keep
430             // surpressing this then http://crbug.com/467288
431             if (!record->hasAttr<DLLExportAttr>())
432               ReportIfSpellingLocNotIgnored(record_location,
433                                             diag_no_explicit_copy_ctor_);
434           } else {
435             // See the comment in the previous branch about copy constructors.
436             // This does the same for implicit move constructors.
437             bool is_likely_compiler_generated_dllexport_move_ctor =
438                 it->isMoveConstructor() &&
439                 !record->hasUserDeclaredMoveConstructor() &&
440                 record->hasAttr<DLLExportAttr>();
441             if (!is_likely_compiler_generated_dllexport_move_ctor)
442               ReportIfSpellingLocNotIgnored(it->getInnerLocStart(),
443                                             diag_inline_complex_ctor_);
444           }
445         } else if (it->isInlined() && !it->isInlineSpecified() &&
446                    !it->isDeleted() && (!it->isCopyOrMoveConstructor() ||
447                                         it->isExplicitlyDefaulted())) {
448           // isInlined() is a more reliable check than hasInlineBody(), but
449           // unfortunately, it results in warnings for implicit copy/move
450           // constructors in the previously mentioned situation. To preserve
451           // compatibility with existing Chromium code, only warn if it's an
452           // explicitly defaulted copy or move constructor.
453           ReportIfSpellingLocNotIgnored(it->getInnerLocStart(),
454                                         diag_inline_complex_ctor_);
455         }
456       }
457     }
458   }
459 
460   // The destructor side is equivalent except that we don't check for
461   // trivial members; 20 ints don't need a destructor.
462   if (dtor_score >= 10 && !record->hasTrivialDestructor()) {
463     if (!record->hasUserDeclaredDestructor()) {
464       ReportIfSpellingLocNotIgnored(record_location, diag_no_explicit_dtor_);
465     } else if (CXXDestructorDecl* dtor = record->getDestructor()) {
466       if (dtor->isInlined() && !dtor->isInlineSpecified() &&
467           !dtor->isDeleted()) {
468         ReportIfSpellingLocNotIgnored(dtor->getInnerLocStart(),
469                                       diag_inline_complex_dtor_);
470       }
471     }
472   }
473 }
474 
475 SuppressibleDiagnosticBuilder
ReportIfSpellingLocNotIgnored(SourceLocation loc,unsigned diagnostic_id)476 FindBadConstructsConsumer::ReportIfSpellingLocNotIgnored(
477     SourceLocation loc,
478     unsigned diagnostic_id) {
479   LocationType type =
480       ClassifyLocation(instance().getSourceManager().getSpellingLoc(loc));
481   bool ignored = type == LocationType::kThirdParty;
482   if (type == LocationType::kBlink) {
483     if (diagnostic_id == diag_no_explicit_ctor_ ||
484         diagnostic_id == diag_no_explicit_copy_ctor_ ||
485         diagnostic_id == diag_inline_complex_ctor_ ||
486         diagnostic_id == diag_no_explicit_dtor_ ||
487         diagnostic_id == diag_inline_complex_dtor_ ||
488         diagnostic_id == diag_refcounted_with_protected_non_virtual_dtor_ ||
489         diagnostic_id == diag_virtual_with_inline_body_) {
490       // Certain checks are ignored in Blink for historical reasons.
491       // TODO(dcheng): Make this list smaller.
492       ignored = true;
493     }
494   }
495   return SuppressibleDiagnosticBuilder(&diagnostic(), loc, diagnostic_id,
496                                        ignored);
497 }
498 
499 // Checks that virtual methods are correctly annotated, and have no body in a
500 // header file.
CheckVirtualMethods(SourceLocation record_location,CXXRecordDecl * record,bool warn_on_inline_bodies)501 void FindBadConstructsConsumer::CheckVirtualMethods(
502     SourceLocation record_location,
503     CXXRecordDecl* record,
504     bool warn_on_inline_bodies) {
505   if (IsGmockObject(record)) {
506     if (!options_.check_gmock_objects)
507       return;
508     warn_on_inline_bodies = false;
509   }
510 
511   for (CXXRecordDecl::method_iterator it = record->method_begin();
512        it != record->method_end();
513        ++it) {
514     if (it->isCopyAssignmentOperator() || isa<CXXConstructorDecl>(*it)) {
515       // Ignore constructors and assignment operators.
516     } else if (isa<CXXDestructorDecl>(*it) &&
517                !record->hasUserDeclaredDestructor()) {
518       // Ignore non-user-declared destructors.
519     } else if (!it->isVirtual()) {
520       continue;
521     } else {
522       CheckVirtualSpecifiers(*it);
523       if (warn_on_inline_bodies)
524         CheckVirtualBodies(*it);
525     }
526   }
527 }
528 
529 // Makes sure that virtual methods use the most appropriate specifier. If a
530 // virtual method overrides a method from a base class, only the override
531 // specifier should be used. If the method should not be overridden by derived
532 // classes, only the final specifier should be used.
CheckVirtualSpecifiers(const CXXMethodDecl * method)533 void FindBadConstructsConsumer::CheckVirtualSpecifiers(
534     const CXXMethodDecl* method) {
535   bool is_override = method->size_overridden_methods() > 0;
536   bool has_virtual = method->isVirtualAsWritten();
537   OverrideAttr* override_attr = method->getAttr<OverrideAttr>();
538   FinalAttr* final_attr = method->getAttr<FinalAttr>();
539 
540   if (IsMethodInTestingNamespace(method))
541     return;
542 
543   SourceManager& manager = instance().getSourceManager();
544   const LangOptions& lang_opts = instance().getLangOpts();
545 
546   // Grab the stream of tokens from the beginning of the method
547   bool remove_virtual = false;
548   bool add_override = false;
549 
550   // Complain if a method is annotated virtual && (override || final).
551   if (has_virtual && (override_attr || final_attr))
552     remove_virtual = true;
553 
554   // Complain if a method is an override and is not annotated with override or
555   // final.
556   if (is_override && !override_attr && !final_attr) {
557     add_override = true;
558     // Also remove the virtual in the same fixit if currently present.
559     if (has_virtual)
560       remove_virtual = true;
561   }
562 
563   if (final_attr && override_attr) {
564     ReportIfSpellingLocNotIgnored(override_attr->getLocation(),
565                                   diag_redundant_virtual_specifier_)
566         << override_attr << final_attr
567         << FixItHint::CreateRemoval(override_attr->getRange());
568   }
569 
570   if (!remove_virtual && !add_override)
571     return;
572 
573   // Deletion of virtual and insertion of override are tricky. The AST does not
574   // expose the location of `virtual` or `=`: the former is useful when trying
575   // to remove `virtual, while the latter is useful when trying to insert
576   // `override`. Iterate over the tokens from |method->getLocStart()| until:
577   // 1. A `{` not nested inside parentheses is found or
578   // 2. A `=` not nested inside parentheses is found or
579   // 3. A `;` not nested inside parentheses is found or
580   // 4. The end of the file is found.
581   SourceLocation virtual_loc;
582   SourceLocation override_insertion_loc;
583   // Attempt to set up the lexer in raw mode.
584   std::pair<FileID, unsigned> decomposed_start =
585       manager.getDecomposedLoc(method->getLocStart());
586   bool invalid = false;
587   StringRef buffer = manager.getBufferData(decomposed_start.first, &invalid);
588   if (!invalid) {
589     int nested_parentheses = 0;
590     Lexer lexer(manager.getLocForStartOfFile(decomposed_start.first), lang_opts,
591                 buffer.begin(), buffer.begin() + decomposed_start.second,
592                 buffer.end());
593     Token token;
594     while (!lexer.LexFromRawLexer(token)) {
595       // Found '=', ';', or '{'. No need to scan any further, since an override
596       // fixit hint won't be inserted after any of these tokens.
597       if ((token.is(tok::equal) || token.is(tok::semi) ||
598            token.is(tok::l_brace)) &&
599           nested_parentheses == 0) {
600         override_insertion_loc = token.getLocation();
601         break;
602       }
603       if (token.is(tok::l_paren)) {
604         ++nested_parentheses;
605       } else if (token.is(tok::r_paren)) {
606         --nested_parentheses;
607       } else if (token.is(tok::raw_identifier)) {
608         // TODO(dcheng): Unclear if this needs to check for nested parentheses
609         // as well?
610         if (token.getRawIdentifier() == "virtual")
611           virtual_loc = token.getLocation();
612       }
613     }
614   }
615 
616   if (add_override && override_insertion_loc.isValid()) {
617     ReportIfSpellingLocNotIgnored(override_insertion_loc,
618                                   diag_method_requires_override_)
619         << FixItHint::CreateInsertion(override_insertion_loc, " override");
620   }
621   if (remove_virtual && virtual_loc.isValid()) {
622     ReportIfSpellingLocNotIgnored(
623         virtual_loc, add_override ? diag_will_be_redundant_virtual_specifier_
624                                   : diag_redundant_virtual_specifier_)
625         << "'virtual'"
626         // Slightly subtle: the else case handles both the currently and the
627         // will be redundant case for override. Doing the check this way also
628         // lets the plugin prioritize keeping 'final' over 'override' when both
629         // are present.
630         << (final_attr ? "'final'" : "'override'")
631         << FixItHint::CreateRemoval(
632                CharSourceRange::getTokenRange(SourceRange(virtual_loc)));
633   }
634 }
635 
CheckVirtualBodies(const CXXMethodDecl * method)636 void FindBadConstructsConsumer::CheckVirtualBodies(
637     const CXXMethodDecl* method) {
638   // Virtual methods should not have inline definitions beyond "{}". This
639   // only matters for header files.
640   if (method->hasBody() && method->hasInlineBody()) {
641     if (CompoundStmt* cs = dyn_cast<CompoundStmt>(method->getBody())) {
642       if (cs->size()) {
643         SourceLocation loc = cs->getLBracLoc();
644         // CR_BEGIN_MSG_MAP_EX and BEGIN_SAFE_MSG_MAP_EX try to be compatible
645         // to BEGIN_MSG_MAP(_EX).  So even though they are in chrome code,
646         // we can't easily fix them, so explicitly whitelist them here.
647         bool emit = true;
648         if (loc.isMacroID()) {
649           SourceManager& manager = instance().getSourceManager();
650           LocationType type = ClassifyLocation(manager.getSpellingLoc(loc));
651           if (type == LocationType::kThirdParty || type == LocationType::kBlink)
652             emit = false;
653           else {
654             StringRef name = Lexer::getImmediateMacroName(
655                 loc, manager, instance().getLangOpts());
656             if (name == "CR_BEGIN_MSG_MAP_EX" ||
657                 name == "BEGIN_SAFE_MSG_MAP_EX")
658               emit = false;
659           }
660         }
661         if (emit)
662           ReportIfSpellingLocNotIgnored(loc, diag_virtual_with_inline_body_);
663       }
664     }
665   }
666 }
667 
CountType(const Type * type,int * trivial_member,int * non_trivial_member,int * templated_non_trivial_member)668 void FindBadConstructsConsumer::CountType(const Type* type,
669                                           int* trivial_member,
670                                           int* non_trivial_member,
671                                           int* templated_non_trivial_member) {
672   switch (type->getTypeClass()) {
673     case Type::Record: {
674       auto* record_decl = type->getAsCXXRecordDecl();
675       // Simplifying; the whole class isn't trivial if the dtor is, but
676       // we use this as a signal about complexity.
677       // Note that if a record doesn't have a definition, it doesn't matter how
678       // it's counted, since the translation unit will fail to build. In that
679       // case, just count it as a trivial member to avoid emitting warnings that
680       // might be spurious.
681       if (!record_decl->hasDefinition() || record_decl->hasTrivialDestructor())
682         (*trivial_member)++;
683       else
684         (*non_trivial_member)++;
685       break;
686     }
687     case Type::TemplateSpecialization: {
688       TemplateName name =
689           dyn_cast<TemplateSpecializationType>(type)->getTemplateName();
690       bool whitelisted_template = false;
691 
692       // HACK: I'm at a loss about how to get the syntax checker to get
693       // whether a template is externed or not. For the first pass here,
694       // just do simple string comparisons.
695       if (TemplateDecl* decl = name.getAsTemplateDecl()) {
696         std::string base_name = decl->getNameAsString();
697         if (base_name == "basic_string")
698           whitelisted_template = true;
699       }
700 
701       if (whitelisted_template)
702         (*non_trivial_member)++;
703       else
704         (*templated_non_trivial_member)++;
705       break;
706     }
707     case Type::Elaborated: {
708       CountType(dyn_cast<ElaboratedType>(type)->getNamedType().getTypePtr(),
709                 trivial_member,
710                 non_trivial_member,
711                 templated_non_trivial_member);
712       break;
713     }
714     case Type::Typedef: {
715       while (const TypedefType* TT = dyn_cast<TypedefType>(type)) {
716         if (auto* decl = TT->getDecl()) {
717           const std::string name = decl->getNameAsString();
718           auto* context = decl->getDeclContext();
719           if (name == "atomic_int" && context->isStdNamespace()) {
720             (*trivial_member)++;
721             return;
722           }
723           type = decl->getUnderlyingType().getTypePtr();
724         }
725       }
726       CountType(type,
727                 trivial_member,
728                 non_trivial_member,
729                 templated_non_trivial_member);
730       break;
731     }
732     default: {
733       // Stupid assumption: anything we see that isn't the above is a POD
734       // or reference type.
735       (*trivial_member)++;
736       break;
737     }
738   }
739 }
740 
741 // Check |record| for issues that are problematic for ref-counted types.
742 // Note that |record| may not be a ref-counted type, but a base class for
743 // a type that is.
744 // If there are issues, update |loc| with the SourceLocation of the issue
745 // and returns appropriately, or returns None if there are no issues.
746 // static
747 FindBadConstructsConsumer::RefcountIssue
CheckRecordForRefcountIssue(const CXXRecordDecl * record,SourceLocation & loc)748 FindBadConstructsConsumer::CheckRecordForRefcountIssue(
749     const CXXRecordDecl* record,
750     SourceLocation& loc) {
751   if (!record->hasUserDeclaredDestructor()) {
752     loc = record->getLocation();
753     return ImplicitDestructor;
754   }
755 
756   if (CXXDestructorDecl* dtor = record->getDestructor()) {
757     if (dtor->getAccess() == AS_public) {
758       loc = dtor->getInnerLocStart();
759       return PublicDestructor;
760     }
761   }
762 
763   return None;
764 }
765 
766 // Returns true if |base| specifies one of the Chromium reference counted
767 // classes (base::RefCounted / base::RefCountedThreadSafe).
IsRefCounted(const CXXBaseSpecifier * base,CXXBasePath & path)768 bool FindBadConstructsConsumer::IsRefCounted(
769     const CXXBaseSpecifier* base,
770     CXXBasePath& path) {
771   const TemplateSpecializationType* base_type =
772       dyn_cast<TemplateSpecializationType>(
773           UnwrapType(base->getType().getTypePtr()));
774   if (!base_type) {
775     // Base-most definition is not a template, so this cannot derive from
776     // base::RefCounted. However, it may still be possible to use with a
777     // scoped_refptr<> and support ref-counting, so this is not a perfect
778     // guarantee of safety.
779     return false;
780   }
781 
782   TemplateName name = base_type->getTemplateName();
783   if (TemplateDecl* decl = name.getAsTemplateDecl()) {
784     std::string base_name = decl->getNameAsString();
785 
786     // Check for both base::RefCounted and base::RefCountedThreadSafe.
787     if (base_name.compare(0, 10, "RefCounted") == 0 &&
788         GetNamespace(decl) == "base") {
789       return true;
790     }
791   }
792 
793   return false;
794 }
795 
796 // Returns true if |base| specifies a class that has a public destructor,
797 // either explicitly or implicitly.
798 // static
HasPublicDtorCallback(const CXXBaseSpecifier * base,CXXBasePath & path,void * user_data)799 bool FindBadConstructsConsumer::HasPublicDtorCallback(
800     const CXXBaseSpecifier* base,
801     CXXBasePath& path,
802     void* user_data) {
803   // Only examine paths that have public inheritance, as they are the
804   // only ones which will result in the destructor potentially being
805   // exposed. This check is largely redundant, as Chromium code should be
806   // exclusively using public inheritance.
807   if (path.Access != AS_public)
808     return false;
809 
810   CXXRecordDecl* record =
811       dyn_cast<CXXRecordDecl>(base->getType()->getAs<RecordType>()->getDecl());
812   SourceLocation unused;
813   return None != CheckRecordForRefcountIssue(record, unused);
814 }
815 
816 // Outputs a C++ inheritance chain as a diagnostic aid.
PrintInheritanceChain(const CXXBasePath & path)817 void FindBadConstructsConsumer::PrintInheritanceChain(const CXXBasePath& path) {
818   for (CXXBasePath::const_iterator it = path.begin(); it != path.end(); ++it) {
819     diagnostic().Report(it->Base->getLocStart(), diag_note_inheritance_)
820         << it->Class << it->Base->getType();
821   }
822 }
823 
DiagnosticForIssue(RefcountIssue issue)824 unsigned FindBadConstructsConsumer::DiagnosticForIssue(RefcountIssue issue) {
825   switch (issue) {
826     case ImplicitDestructor:
827       return diag_refcounted_needs_explicit_dtor_;
828     case PublicDestructor:
829       return diag_refcounted_with_public_dtor_;
830     case None:
831       assert(false && "Do not call DiagnosticForIssue with issue None");
832       return 0;
833   }
834   assert(false);
835   return 0;
836 }
837 
838 // Check |record| to determine if it has any problematic refcounting
839 // issues and, if so, print them as warnings/errors based on the current
840 // value of getErrorLevel().
841 //
842 // If |record| is a C++ class, and if it inherits from one of the Chromium
843 // ref-counting classes (base::RefCounted / base::RefCountedThreadSafe),
844 // ensure that there are no public destructors in the class hierarchy. This
845 // is to guard against accidentally stack-allocating a RefCounted class or
846 // sticking it in a non-ref-counted container (like std::unique_ptr<>).
CheckRefCountedDtors(SourceLocation record_location,CXXRecordDecl * record)847 void FindBadConstructsConsumer::CheckRefCountedDtors(
848     SourceLocation record_location,
849     CXXRecordDecl* record) {
850   // Skip anonymous structs.
851   if (record->getIdentifier() == NULL)
852     return;
853 
854   // Determine if the current type is even ref-counted.
855   CXXBasePaths refcounted_path;
856   if (!record->lookupInBases(
857           [this](const CXXBaseSpecifier* base, CXXBasePath& path) {
858             return IsRefCounted(base, path);
859           },
860           refcounted_path)) {
861     return;  // Class does not derive from a ref-counted base class.
862   }
863 
864   // Easy check: Check to see if the current type is problematic.
865   SourceLocation loc;
866   RefcountIssue issue = CheckRecordForRefcountIssue(record, loc);
867   if (issue != None) {
868     diagnostic().Report(loc, DiagnosticForIssue(issue));
869     PrintInheritanceChain(refcounted_path.front());
870     return;
871   }
872   if (CXXDestructorDecl* dtor =
873           refcounted_path.begin()->back().Class->getDestructor()) {
874     if (dtor->getAccess() == AS_protected && !dtor->isVirtual()) {
875       loc = dtor->getInnerLocStart();
876       ReportIfSpellingLocNotIgnored(
877           loc, diag_refcounted_with_protected_non_virtual_dtor_);
878       return;
879     }
880   }
881 
882   // Long check: Check all possible base classes for problematic
883   // destructors. This checks for situations involving multiple
884   // inheritance, where the ref-counted class may be implementing an
885   // interface that has a public or implicit destructor.
886   //
887   // struct SomeInterface {
888   //   virtual void DoFoo();
889   // };
890   //
891   // struct RefCountedInterface
892   //    : public base::RefCounted<RefCountedInterface>,
893   //      public SomeInterface {
894   //  private:
895   //   friend class base::Refcounted<RefCountedInterface>;
896   //   virtual ~RefCountedInterface() {}
897   // };
898   //
899   // While RefCountedInterface is "safe", in that its destructor is
900   // private, it's possible to do the following "unsafe" code:
901   //   scoped_refptr<RefCountedInterface> some_class(
902   //       new RefCountedInterface);
903   //   // Calls SomeInterface::~SomeInterface(), which is unsafe.
904   //   delete static_cast<SomeInterface*>(some_class.get());
905   if (!options_.check_base_classes)
906     return;
907 
908   // Find all public destructors. This will record the class hierarchy
909   // that leads to the public destructor in |dtor_paths|.
910   CXXBasePaths dtor_paths;
911   if (!record->lookupInBases(
912           [](const CXXBaseSpecifier* base, CXXBasePath& path) {
913             // TODO(thakis): Inline HasPublicDtorCallback() after clang roll.
914             return HasPublicDtorCallback(base, path, nullptr);
915           },
916           dtor_paths)) {
917     return;
918   }
919 
920   for (CXXBasePaths::const_paths_iterator it = dtor_paths.begin();
921        it != dtor_paths.end();
922        ++it) {
923     // The record with the problem will always be the last record
924     // in the path, since it is the record that stopped the search.
925     const CXXRecordDecl* problem_record = dyn_cast<CXXRecordDecl>(
926         it->back().Base->getType()->getAs<RecordType>()->getDecl());
927 
928     issue = CheckRecordForRefcountIssue(problem_record, loc);
929 
930     if (issue == ImplicitDestructor) {
931       diagnostic().Report(record_location,
932                           diag_refcounted_needs_explicit_dtor_);
933       PrintInheritanceChain(refcounted_path.front());
934       diagnostic().Report(loc, diag_note_implicit_dtor_) << problem_record;
935       PrintInheritanceChain(*it);
936     } else if (issue == PublicDestructor) {
937       diagnostic().Report(record_location, diag_refcounted_with_public_dtor_);
938       PrintInheritanceChain(refcounted_path.front());
939       diagnostic().Report(loc, diag_note_public_dtor_);
940       PrintInheritanceChain(*it);
941     }
942   }
943 }
944 
945 // Check for any problems with WeakPtrFactory class members. This currently
946 // only checks that any WeakPtrFactory<T> member of T appears as the last
947 // data member in T. We could consider checking for bad uses of
948 // WeakPtrFactory to refer to other data members, but that would require
949 // looking at the initializer list in constructors to see what the factory
950 // points to.
951 // Note, if we later add other unrelated checks of data members, we should
952 // consider collapsing them in to one loop to avoid iterating over the data
953 // members more than once.
CheckWeakPtrFactoryMembers(SourceLocation record_location,CXXRecordDecl * record)954 void FindBadConstructsConsumer::CheckWeakPtrFactoryMembers(
955     SourceLocation record_location,
956     CXXRecordDecl* record) {
957   // Skip anonymous structs.
958   if (record->getIdentifier() == NULL)
959     return;
960 
961   // Iterate through members of the class.
962   RecordDecl::field_iterator iter(record->field_begin()),
963       the_end(record->field_end());
964   SourceLocation weak_ptr_factory_location;  // Invalid initially.
965   for (; iter != the_end; ++iter) {
966     const TemplateSpecializationType* template_spec_type =
967         iter->getType().getTypePtr()->getAs<TemplateSpecializationType>();
968     bool param_is_weak_ptr_factory_to_self = false;
969     if (template_spec_type) {
970       const TemplateDecl* template_decl =
971           template_spec_type->getTemplateName().getAsTemplateDecl();
972       if (template_decl && template_spec_type->getNumArgs() == 1) {
973         if (template_decl->getNameAsString().compare("WeakPtrFactory") == 0 &&
974             GetNamespace(template_decl) == "base") {
975           // Only consider WeakPtrFactory members which are specialized for the
976           // owning class.
977           const TemplateArgument& arg = template_spec_type->getArg(0);
978           if (arg.getAsType().getTypePtr()->getAsCXXRecordDecl() ==
979               record->getTypeForDecl()->getAsCXXRecordDecl()) {
980             if (!weak_ptr_factory_location.isValid()) {
981               // Save the first matching WeakPtrFactory member for the
982               // diagnostic.
983               weak_ptr_factory_location = iter->getLocation();
984             }
985             param_is_weak_ptr_factory_to_self = true;
986           }
987         }
988       }
989     }
990     // If we've already seen a WeakPtrFactory<OwningType> and this param is not
991     // one of those, it means there is at least one member after a factory.
992     if (weak_ptr_factory_location.isValid() &&
993         !param_is_weak_ptr_factory_to_self) {
994       ReportIfSpellingLocNotIgnored(weak_ptr_factory_location,
995                                     diag_weak_ptr_factory_order_);
996     }
997   }
998 }
999 
1000 // Copied from BlinkGCPlugin, see crrev.com/1135333007
ParseFunctionTemplates(TranslationUnitDecl * decl)1001 void FindBadConstructsConsumer::ParseFunctionTemplates(
1002     TranslationUnitDecl* decl) {
1003   if (!instance().getLangOpts().DelayedTemplateParsing)
1004     return;  // Nothing to do.
1005 
1006   std::set<FunctionDecl*> late_parsed_decls = GetLateParsedFunctionDecls(decl);
1007   clang::Sema& sema = instance().getSema();
1008 
1009   for (const FunctionDecl* fd : late_parsed_decls) {
1010     assert(fd->isLateTemplateParsed());
1011 
1012     if (instance().getSourceManager().isInSystemHeader(
1013             instance().getSourceManager().getSpellingLoc(fd->getLocation())))
1014       continue;
1015 
1016     // Parse and build AST for yet-uninstantiated template functions.
1017     clang::LateParsedTemplate* lpt = sema.LateParsedTemplateMap[fd].get();
1018     sema.LateTemplateParser(sema.OpaqueParser, *lpt);
1019   }
1020 }
1021 
CheckVarDecl(clang::VarDecl * var_decl)1022 void FindBadConstructsConsumer::CheckVarDecl(clang::VarDecl* var_decl) {
1023   // Lambda init-captures should be ignored.
1024   if (var_decl->isInitCapture())
1025     return;
1026 
1027   // Check whether auto deduces to a raw pointer.
1028   QualType non_reference_type = var_decl->getType().getNonReferenceType();
1029   // We might have a case where the type is written as auto*, but the actual
1030   // type is deduced to be an int**. For that reason, keep going down the
1031   // pointee type until we get an 'auto' or a non-pointer type.
1032   for (;;) {
1033     const clang::AutoType* auto_type =
1034         non_reference_type->getAs<clang::AutoType>();
1035     if (auto_type) {
1036       if (auto_type->isDeduced()) {
1037         QualType deduced_type = auto_type->getDeducedType();
1038         if (!deduced_type.isNull() && deduced_type->isPointerType() &&
1039             !deduced_type->isFunctionPointerType()) {
1040           // Check if we should even be considering this type (note that there
1041           // should be fewer auto types than banned namespace/directory types,
1042           // so check this last.
1043           LocationType location_type =
1044               ClassifyLocation(var_decl->getLocStart());
1045           if (location_type != LocationType::kThirdParty) {
1046             // The range starts from |var_decl|'s loc start, which is the
1047             // beginning of the full expression defining this |var_decl|. It
1048             // ends, however, where this |var_decl|'s type loc ends, since
1049             // that's the end of the type of |var_decl|.
1050             // Note that the beginning source location of type loc omits cv
1051             // qualifiers, which is why it's not a good candidate to use for the
1052             // start of the range.
1053             clang::SourceRange range(
1054                 var_decl->getLocStart(),
1055                 var_decl->getTypeSourceInfo()->getTypeLoc().getLocEnd());
1056             ReportIfSpellingLocNotIgnored(range.getBegin(),
1057                                           diag_auto_deduced_to_a_pointer_type_)
1058                 << FixItHint::CreateReplacement(
1059                        range,
1060                        GetAutoReplacementTypeAsString(
1061                            var_decl->getType(), var_decl->getStorageClass()));
1062           }
1063         }
1064       }
1065     } else if (non_reference_type->isPointerType()) {
1066       non_reference_type = non_reference_type->getPointeeType();
1067       continue;
1068     }
1069     break;
1070   }
1071 }
1072 
1073 }  // namespace chrome_checker
1074