1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 /* This file respects the LLVM coding standard described at
6 * http://llvm.org/docs/CodingStandards.html */
7
8 #include "clang/AST/ASTConsumer.h"
9 #include "clang/AST/ASTContext.h"
10 #include "clang/AST/RecursiveASTVisitor.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
12 #include "clang/ASTMatchers/ASTMatchers.h"
13 #include "clang/Basic/Version.h"
14 #include "clang/Frontend/CompilerInstance.h"
15 #include "clang/Frontend/FrontendPluginRegistry.h"
16 #include "clang/Frontend/MultiplexConsumer.h"
17 #include "clang/Sema/Sema.h"
18 #include "llvm/ADT/DenseMap.h"
19 #include "llvm/Support/FileSystem.h"
20 #include "llvm/Support/Path.h"
21 #include <memory>
22 #include <iterator>
23
24 #define CLANG_VERSION_FULL (CLANG_VERSION_MAJOR * 100 + CLANG_VERSION_MINOR)
25
26 using namespace llvm;
27 using namespace clang;
28
29 #if CLANG_VERSION_FULL >= 306
30 typedef std::unique_ptr<ASTConsumer> ASTConsumerPtr;
31 #else
32 typedef ASTConsumer *ASTConsumerPtr;
33 #endif
34
35 #ifndef HAVE_NEW_ASTMATCHER_NAMES
36 // In clang 3.8, a number of AST matchers were renamed to better match the
37 // respective AST node. We use the new names, and #define them to the old
38 // ones for compatibility with older versions.
39 #define cxxConstructExpr constructExpr
40 #define cxxConstructorDecl constructorDecl
41 #define cxxMethodDecl methodDecl
42 #define cxxNewExpr newExpr
43 #define cxxRecordDecl recordDecl
44 #endif
45
46 #ifndef HAS_ACCEPTS_IGNORINGPARENIMPCASTS
47 #define hasIgnoringParenImpCasts(x) has(x)
48 #else
49 // Before clang 3.9 "has" would behave like has(ignoringParenImpCasts(x)),
50 // however doing that explicitly would not compile.
51 #define hasIgnoringParenImpCasts(x) has(ignoringParenImpCasts(x))
52 #endif
53
54 // Check if the given expression contains an assignment expression.
55 // This can either take the form of a Binary Operator or a
56 // Overloaded Operator Call.
hasSideEffectAssignment(const Expr * Expression)57 bool hasSideEffectAssignment(const Expr *Expression) {
58 if (auto OpCallExpr = dyn_cast_or_null<CXXOperatorCallExpr>(Expression)) {
59 auto BinOp = OpCallExpr->getOperator();
60 if (BinOp == OO_Equal || (BinOp >= OO_PlusEqual && BinOp <= OO_PipeEqual)) {
61 return true;
62 }
63 } else if (auto BinOpExpr = dyn_cast_or_null<BinaryOperator>(Expression)) {
64 if (BinOpExpr->isAssignmentOp()) {
65 return true;
66 }
67 }
68
69 // Recurse to children.
70 for (const Stmt *SubStmt : Expression->children()) {
71 auto ChildExpr = dyn_cast_or_null<Expr>(SubStmt);
72 if (ChildExpr && hasSideEffectAssignment(ChildExpr)) {
73 return true;
74 }
75 }
76
77 return false;
78 }
79
80 namespace {
81
82 using namespace clang::ast_matchers;
83 class DiagnosticsMatcher {
84 public:
85 DiagnosticsMatcher();
86
makeASTConsumer()87 ASTConsumerPtr makeASTConsumer() { return AstMatcher.newASTConsumer(); }
88
89 private:
90 class ScopeChecker : public MatchFinder::MatchCallback {
91 public:
92 virtual void run(const MatchFinder::MatchResult &Result);
93 };
94
95 class ArithmeticArgChecker : public MatchFinder::MatchCallback {
96 public:
97 virtual void run(const MatchFinder::MatchResult &Result);
98 };
99
100 class TrivialCtorDtorChecker : public MatchFinder::MatchCallback {
101 public:
102 virtual void run(const MatchFinder::MatchResult &Result);
103 };
104
105 class NaNExprChecker : public MatchFinder::MatchCallback {
106 public:
107 virtual void run(const MatchFinder::MatchResult &Result);
108 };
109
110 class NoAddRefReleaseOnReturnChecker : public MatchFinder::MatchCallback {
111 public:
112 virtual void run(const MatchFinder::MatchResult &Result);
113 };
114
115 class RefCountedInsideLambdaChecker : public MatchFinder::MatchCallback {
116 public:
117 virtual void run(const MatchFinder::MatchResult &Result);
118 void emitDiagnostics(SourceLocation Loc, StringRef Name, QualType Type);
119
120 private:
121 class ThisVisitor : public RecursiveASTVisitor<ThisVisitor> {
122 public:
ThisVisitor(RefCountedInsideLambdaChecker & Checker)123 explicit ThisVisitor(RefCountedInsideLambdaChecker& Checker)
124 : Checker(Checker) {}
125
126 bool VisitCXXThisExpr(CXXThisExpr *This);
127 private:
128 RefCountedInsideLambdaChecker& Checker;
129 };
130
131 ASTContext *Context;
132 };
133
134 class ExplicitOperatorBoolChecker : public MatchFinder::MatchCallback {
135 public:
136 virtual void run(const MatchFinder::MatchResult &Result);
137 };
138
139 class NoDuplicateRefCntMemberChecker : public MatchFinder::MatchCallback {
140 public:
141 virtual void run(const MatchFinder::MatchResult &Result);
142 };
143
144 class NeedsNoVTableTypeChecker : public MatchFinder::MatchCallback {
145 public:
146 virtual void run(const MatchFinder::MatchResult &Result);
147 };
148
149 class NonMemMovableTemplateArgChecker : public MatchFinder::MatchCallback {
150 public:
151 virtual void run(const MatchFinder::MatchResult &Result);
152 };
153
154 class NonMemMovableMemberChecker : public MatchFinder::MatchCallback {
155 public:
156 virtual void run(const MatchFinder::MatchResult &Result);
157 };
158
159 class ExplicitImplicitChecker : public MatchFinder::MatchCallback {
160 public:
161 virtual void run(const MatchFinder::MatchResult &Result);
162 };
163
164 class NoAutoTypeChecker : public MatchFinder::MatchCallback {
165 public:
166 virtual void run(const MatchFinder::MatchResult &Result);
167 };
168
169 class NoExplicitMoveConstructorChecker : public MatchFinder::MatchCallback {
170 public:
171 virtual void run(const MatchFinder::MatchResult &Result);
172 };
173
174 class RefCountedCopyConstructorChecker : public MatchFinder::MatchCallback {
175 public:
176 virtual void run(const MatchFinder::MatchResult &Result);
177 };
178
179 class AssertAssignmentChecker : public MatchFinder::MatchCallback {
180 public:
181 virtual void run(const MatchFinder::MatchResult &Result);
182 };
183
184 class KungFuDeathGripChecker : public MatchFinder::MatchCallback {
185 public:
186 virtual void run(const MatchFinder::MatchResult &Result);
187 };
188
189 class SprintfLiteralChecker : public MatchFinder::MatchCallback {
190 public:
191 virtual void run(const MatchFinder::MatchResult &Result);
192 };
193
194 class OverrideBaseCallChecker : public MatchFinder::MatchCallback {
195 public:
196 virtual void run(const MatchFinder::MatchResult &Result);
197 private:
198 void evaluateExpression(const Stmt *StmtExpr,
199 std::list<const CXXMethodDecl*> &MethodList);
200 void getRequiredBaseMethod(const CXXMethodDecl* Method,
201 std::list<const CXXMethodDecl*>& MethodsList);
202 void findBaseMethodCall(const CXXMethodDecl* Method,
203 std::list<const CXXMethodDecl*>& MethodsList);
204 bool isRequiredBaseMethod(const CXXMethodDecl *Method);
205 };
206
207 /*
208 * This is a companion checker for OverrideBaseCallChecker that rejects
209 * the usage of MOZ_REQUIRED_BASE_METHOD on non-virtual base methods.
210 */
211 class OverrideBaseCallUsageChecker : public MatchFinder::MatchCallback {
212 public:
213 virtual void run(const MatchFinder::MatchResult &Result);
214 };
215
216 class NonParamInsideFunctionDeclChecker : public MatchFinder::MatchCallback {
217 public:
218 virtual void run(const MatchFinder::MatchResult &Result);
219 };
220
221 ScopeChecker Scope;
222 ArithmeticArgChecker ArithmeticArg;
223 TrivialCtorDtorChecker TrivialCtorDtor;
224 NaNExprChecker NaNExpr;
225 NoAddRefReleaseOnReturnChecker NoAddRefReleaseOnReturn;
226 RefCountedInsideLambdaChecker RefCountedInsideLambda;
227 ExplicitOperatorBoolChecker ExplicitOperatorBool;
228 NoDuplicateRefCntMemberChecker NoDuplicateRefCntMember;
229 NeedsNoVTableTypeChecker NeedsNoVTableType;
230 NonMemMovableTemplateArgChecker NonMemMovableTemplateArg;
231 NonMemMovableMemberChecker NonMemMovableMember;
232 ExplicitImplicitChecker ExplicitImplicit;
233 NoAutoTypeChecker NoAutoType;
234 NoExplicitMoveConstructorChecker NoExplicitMoveConstructor;
235 RefCountedCopyConstructorChecker RefCountedCopyConstructor;
236 AssertAssignmentChecker AssertAttribution;
237 KungFuDeathGripChecker KungFuDeathGrip;
238 SprintfLiteralChecker SprintfLiteral;
239 OverrideBaseCallChecker OverrideBaseCall;
240 OverrideBaseCallUsageChecker OverrideBaseCallUsage;
241 NonParamInsideFunctionDeclChecker NonParamInsideFunctionDecl;
242 MatchFinder AstMatcher;
243 };
244
245 namespace {
246
getDeclarationNamespace(const Decl * Declaration)247 std::string getDeclarationNamespace(const Decl *Declaration) {
248 const DeclContext *DC =
249 Declaration->getDeclContext()->getEnclosingNamespaceContext();
250 const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC);
251 if (!ND) {
252 return "";
253 }
254
255 while (const DeclContext *ParentDC = ND->getParent()) {
256 if (!isa<NamespaceDecl>(ParentDC)) {
257 break;
258 }
259 ND = cast<NamespaceDecl>(ParentDC);
260 }
261
262 const auto &Name = ND->getName();
263 return Name;
264 }
265
isInIgnoredNamespaceForImplicitCtor(const Decl * Declaration)266 bool isInIgnoredNamespaceForImplicitCtor(const Decl *Declaration) {
267 std::string Name = getDeclarationNamespace(Declaration);
268 if (Name == "") {
269 return false;
270 }
271
272 return Name == "std" || // standard C++ lib
273 Name == "__gnu_cxx" || // gnu C++ lib
274 Name == "boost" || // boost
275 Name == "webrtc" || // upstream webrtc
276 Name == "rtc" || // upstream webrtc 'base' package
277 Name.substr(0, 4) == "icu_" || // icu
278 Name == "google" || // protobuf
279 Name == "google_breakpad" || // breakpad
280 Name == "soundtouch" || // libsoundtouch
281 Name == "stagefright" || // libstagefright
282 Name == "MacFileUtilities" || // MacFileUtilities
283 Name == "dwarf2reader" || // dwarf2reader
284 Name == "arm_ex_to_module" || // arm_ex_to_module
285 Name == "testing" || // gtest
286 Name == "Json"; // jsoncpp
287 }
288
isInIgnoredNamespaceForImplicitConversion(const Decl * Declaration)289 bool isInIgnoredNamespaceForImplicitConversion(const Decl *Declaration) {
290 std::string Name = getDeclarationNamespace(Declaration);
291 if (Name == "") {
292 return false;
293 }
294
295 return Name == "std" || // standard C++ lib
296 Name == "__gnu_cxx" || // gnu C++ lib
297 Name == "google_breakpad" || // breakpad
298 Name == "testing"; // gtest
299 }
300
isIgnoredPathForImplicitCtor(const Decl * Declaration)301 bool isIgnoredPathForImplicitCtor(const Decl *Declaration) {
302 SourceLocation Loc = Declaration->getLocation();
303 const SourceManager &SM = Declaration->getASTContext().getSourceManager();
304 SmallString<1024> FileName = SM.getFilename(Loc);
305 llvm::sys::fs::make_absolute(FileName);
306 llvm::sys::path::reverse_iterator Begin = llvm::sys::path::rbegin(FileName),
307 End = llvm::sys::path::rend(FileName);
308 for (; Begin != End; ++Begin) {
309 if (Begin->compare_lower(StringRef("skia")) == 0 ||
310 Begin->compare_lower(StringRef("angle")) == 0 ||
311 Begin->compare_lower(StringRef("harfbuzz")) == 0 ||
312 Begin->compare_lower(StringRef("hunspell")) == 0 ||
313 Begin->compare_lower(StringRef("scoped_ptr.h")) == 0 ||
314 Begin->compare_lower(StringRef("graphite2")) == 0 ||
315 Begin->compare_lower(StringRef("icu")) == 0) {
316 return true;
317 }
318 if (Begin->compare_lower(StringRef("chromium")) == 0) {
319 // Ignore security/sandbox/chromium but not ipc/chromium.
320 ++Begin;
321 return Begin != End && Begin->compare_lower(StringRef("sandbox")) == 0;
322 }
323 }
324 return false;
325 }
326
isIgnoredPathForImplicitConversion(const Decl * Declaration)327 bool isIgnoredPathForImplicitConversion(const Decl *Declaration) {
328 Declaration = Declaration->getCanonicalDecl();
329 SourceLocation Loc = Declaration->getLocation();
330 const SourceManager &SM = Declaration->getASTContext().getSourceManager();
331 SmallString<1024> FileName = SM.getFilename(Loc);
332 llvm::sys::fs::make_absolute(FileName);
333 llvm::sys::path::reverse_iterator Begin = llvm::sys::path::rbegin(FileName),
334 End = llvm::sys::path::rend(FileName);
335 for (; Begin != End; ++Begin) {
336 if (Begin->compare_lower(StringRef("graphite2")) == 0) {
337 return true;
338 }
339 if (Begin->compare_lower(StringRef("chromium")) == 0) {
340 // Ignore security/sandbox/chromium but not ipc/chromium.
341 ++Begin;
342 return Begin != End && Begin->compare_lower(StringRef("sandbox")) == 0;
343 }
344 }
345 return false;
346 }
347
isIgnoredPathForSprintfLiteral(const CallExpr * Call,const SourceManager & SM)348 bool isIgnoredPathForSprintfLiteral(const CallExpr *Call, const SourceManager &SM) {
349 SourceLocation Loc = Call->getLocStart();
350 SmallString<1024> FileName = SM.getFilename(Loc);
351 llvm::sys::fs::make_absolute(FileName);
352 llvm::sys::path::reverse_iterator Begin = llvm::sys::path::rbegin(FileName),
353 End = llvm::sys::path::rend(FileName);
354 for (; Begin != End; ++Begin) {
355 if (Begin->compare_lower(StringRef("angle")) == 0 ||
356 Begin->compare_lower(StringRef("chromium")) == 0 ||
357 Begin->compare_lower(StringRef("crashreporter")) == 0 ||
358 Begin->compare_lower(StringRef("google-breakpad")) == 0 ||
359 Begin->compare_lower(StringRef("harfbuzz")) == 0 ||
360 Begin->compare_lower(StringRef("libstagefright")) == 0 ||
361 Begin->compare_lower(StringRef("mtransport")) == 0 ||
362 Begin->compare_lower(StringRef("protobuf")) == 0 ||
363 Begin->compare_lower(StringRef("skia")) == 0 ||
364 // Gtest uses snprintf as GTEST_SNPRINTF_ with sizeof
365 Begin->compare_lower(StringRef("testing")) == 0) {
366 return true;
367 }
368 if (Begin->compare_lower(StringRef("webrtc")) == 0) {
369 // Ignore trunk/webrtc, but not media/webrtc
370 ++Begin;
371 return Begin != End && Begin->compare_lower(StringRef("trunk")) == 0;
372 }
373 }
374 return false;
375 }
376
isInterestingDeclForImplicitConversion(const Decl * Declaration)377 bool isInterestingDeclForImplicitConversion(const Decl *Declaration) {
378 return !isInIgnoredNamespaceForImplicitConversion(Declaration) &&
379 !isIgnoredPathForImplicitConversion(Declaration);
380 }
381
isIgnoredExprForMustUse(const Expr * E)382 bool isIgnoredExprForMustUse(const Expr *E) {
383 if (const CXXOperatorCallExpr *OpCall = dyn_cast<CXXOperatorCallExpr>(E)) {
384 switch (OpCall->getOperator()) {
385 case OO_Equal:
386 case OO_PlusEqual:
387 case OO_MinusEqual:
388 case OO_StarEqual:
389 case OO_SlashEqual:
390 case OO_PercentEqual:
391 case OO_CaretEqual:
392 case OO_AmpEqual:
393 case OO_PipeEqual:
394 case OO_LessLessEqual:
395 case OO_GreaterGreaterEqual:
396 return true;
397 default:
398 return false;
399 }
400 }
401
402 if (const BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) {
403 return Op->isAssignmentOp();
404 }
405
406 return false;
407 }
408
409 template<typename T>
getNameChecked(const T & D)410 StringRef getNameChecked(const T& D) {
411 return D->getIdentifier() ? D->getName() : "";
412 }
413
typeIsRefPtr(QualType Q)414 bool typeIsRefPtr(QualType Q) {
415 CXXRecordDecl *D = Q->getAsCXXRecordDecl();
416 if (!D || !D->getIdentifier()) {
417 return false;
418 }
419
420 StringRef name = D->getName();
421 if (name == "RefPtr" || name == "nsCOMPtr") {
422 return true;
423 }
424 return false;
425 }
426
427 // The method defined in clang for ignoring implicit nodes doesn't work with
428 // some AST trees. To get around this, we define our own implementation of
429 // IgnoreImplicit.
IgnoreImplicit(const Stmt * s)430 const Stmt *IgnoreImplicit(const Stmt *s) {
431 while (true) {
432 if (auto *ewc = dyn_cast<ExprWithCleanups>(s)) {
433 s = ewc->getSubExpr();
434 } else if (auto *mte = dyn_cast<MaterializeTemporaryExpr>(s)) {
435 s = mte->GetTemporaryExpr();
436 } else if (auto *bte = dyn_cast<CXXBindTemporaryExpr>(s)) {
437 s = bte->getSubExpr();
438 } else if (auto *ice = dyn_cast<ImplicitCastExpr>(s)) {
439 s = ice->getSubExpr();
440 } else {
441 break;
442 }
443 }
444
445 return s;
446 }
447
IgnoreImplicit(const Expr * e)448 const Expr *IgnoreImplicit(const Expr *e) {
449 return cast<Expr>(IgnoreImplicit(static_cast<const Stmt *>(e)));
450 }
451 }
452
453 class CustomTypeAnnotation {
454 enum ReasonKind {
455 RK_None,
456 RK_Direct,
457 RK_ArrayElement,
458 RK_BaseClass,
459 RK_Field,
460 RK_TemplateInherited,
461 };
462 struct AnnotationReason {
463 QualType Type;
464 ReasonKind Kind;
465 const FieldDecl *Field;
466
valid__anon640086c70111::CustomTypeAnnotation::AnnotationReason467 bool valid() const { return Kind != RK_None; }
468 };
469 typedef DenseMap<void *, AnnotationReason> ReasonCache;
470
471 const char *Spelling;
472 const char *Pretty;
473 ReasonCache Cache;
474
475 public:
CustomTypeAnnotation(const char * Spelling,const char * Pretty)476 CustomTypeAnnotation(const char *Spelling, const char *Pretty)
477 : Spelling(Spelling), Pretty(Pretty){};
478
~CustomTypeAnnotation()479 virtual ~CustomTypeAnnotation() {}
480
481 // Checks if this custom annotation "effectively affects" the given type.
hasEffectiveAnnotation(QualType T)482 bool hasEffectiveAnnotation(QualType T) {
483 return directAnnotationReason(T).valid();
484 }
485 void dumpAnnotationReason(DiagnosticsEngine &Diag, QualType T,
486 SourceLocation Loc);
487
reportErrorIfPresent(DiagnosticsEngine & Diag,QualType T,SourceLocation Loc,unsigned ErrorID,unsigned NoteID)488 void reportErrorIfPresent(DiagnosticsEngine &Diag, QualType T,
489 SourceLocation Loc, unsigned ErrorID,
490 unsigned NoteID) {
491 if (hasEffectiveAnnotation(T)) {
492 Diag.Report(Loc, ErrorID) << T;
493 Diag.Report(Loc, NoteID);
494 dumpAnnotationReason(Diag, T, Loc);
495 }
496 }
497
498 private:
499 bool hasLiteralAnnotation(QualType T) const;
500 AnnotationReason directAnnotationReason(QualType T);
501 AnnotationReason tmplArgAnnotationReason(ArrayRef<TemplateArgument> Args);
502
503 protected:
504 // Allow subclasses to apply annotations to external code:
hasFakeAnnotation(const TagDecl * D) const505 virtual bool hasFakeAnnotation(const TagDecl *D) const { return false; }
506 };
507
508 static CustomTypeAnnotation StackClass =
509 CustomTypeAnnotation("moz_stack_class", "stack");
510 static CustomTypeAnnotation GlobalClass =
511 CustomTypeAnnotation("moz_global_class", "global");
512 static CustomTypeAnnotation NonHeapClass =
513 CustomTypeAnnotation("moz_nonheap_class", "non-heap");
514 static CustomTypeAnnotation HeapClass =
515 CustomTypeAnnotation("moz_heap_class", "heap");
516 static CustomTypeAnnotation NonTemporaryClass =
517 CustomTypeAnnotation("moz_non_temporary_class", "non-temporary");
518 static CustomTypeAnnotation MustUse =
519 CustomTypeAnnotation("moz_must_use_type", "must-use");
520 static CustomTypeAnnotation NonParam =
521 CustomTypeAnnotation("moz_non_param", "non-param");
522
523 class MemMoveAnnotation final : public CustomTypeAnnotation {
524 public:
MemMoveAnnotation()525 MemMoveAnnotation()
526 : CustomTypeAnnotation("moz_non_memmovable", "non-memmove()able") {}
527
~MemMoveAnnotation()528 virtual ~MemMoveAnnotation() {}
529
530 protected:
hasFakeAnnotation(const TagDecl * D) const531 bool hasFakeAnnotation(const TagDecl *D) const override {
532 // Annotate everything in ::std, with a few exceptions; see bug
533 // 1201314 for discussion.
534 if (getDeclarationNamespace(D) == "std") {
535 // This doesn't check that it's really ::std::pair and not
536 // ::std::something_else::pair, but should be good enough.
537 StringRef Name = getNameChecked(D);
538 if (Name == "pair" || Name == "atomic" || Name == "__atomic_base") {
539 return false;
540 }
541 return true;
542 }
543 return false;
544 }
545 };
546
547 static MemMoveAnnotation NonMemMovable = MemMoveAnnotation();
548
549 class MozChecker : public ASTConsumer, public RecursiveASTVisitor<MozChecker> {
550 DiagnosticsEngine &Diag;
551 const CompilerInstance &CI;
552 DiagnosticsMatcher Matcher;
553
554 public:
MozChecker(const CompilerInstance & CI)555 MozChecker(const CompilerInstance &CI) : Diag(CI.getDiagnostics()), CI(CI) {}
556
getOtherConsumer()557 ASTConsumerPtr getOtherConsumer() { return Matcher.makeASTConsumer(); }
558
HandleTranslationUnit(ASTContext & Ctx)559 virtual void HandleTranslationUnit(ASTContext &Ctx) override {
560 TraverseDecl(Ctx.getTranslationUnitDecl());
561 }
562
hasCustomAnnotation(const Decl * D,const char * Spelling)563 static bool hasCustomAnnotation(const Decl *D, const char *Spelling) {
564 iterator_range<specific_attr_iterator<AnnotateAttr>> Attrs =
565 D->specific_attrs<AnnotateAttr>();
566
567 for (AnnotateAttr *Attr : Attrs) {
568 if (Attr->getAnnotation() == Spelling) {
569 return true;
570 }
571 }
572
573 return false;
574 }
575
handleUnusedExprResult(const Stmt * Statement)576 void handleUnusedExprResult(const Stmt *Statement) {
577 const Expr *E = dyn_cast_or_null<Expr>(Statement);
578 if (E) {
579 E = E->IgnoreImplicit(); // Ignore ExprWithCleanup etc. implicit wrappers
580 QualType T = E->getType();
581 if (MustUse.hasEffectiveAnnotation(T) && !isIgnoredExprForMustUse(E)) {
582 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
583 DiagnosticIDs::Error, "Unused value of must-use type %0");
584
585 Diag.Report(E->getLocStart(), ErrorID) << T;
586 MustUse.dumpAnnotationReason(Diag, T, E->getLocStart());
587 }
588 }
589 }
590
VisitCXXRecordDecl(CXXRecordDecl * D)591 bool VisitCXXRecordDecl(CXXRecordDecl *D) {
592 // We need definitions, not declarations
593 if (!D->isThisDeclarationADefinition())
594 return true;
595
596 // Look through all of our immediate bases to find methods that need to be
597 // overridden
598 typedef std::vector<CXXMethodDecl *> OverridesVector;
599 OverridesVector MustOverrides;
600 for (CXXRecordDecl::base_class_iterator Base = D->bases_begin(),
601 E = D->bases_end();
602 Base != E; ++Base) {
603 // The base is either a class (CXXRecordDecl) or it's a templated class...
604 CXXRecordDecl *Parent = Base->getType()
605 .getDesugaredType(D->getASTContext())
606 ->getAsCXXRecordDecl();
607 // The parent might not be resolved to a type yet. In this case, we can't
608 // do any checking here. For complete correctness, we should visit
609 // template instantiations, but this case is likely to be rare, so we will
610 // ignore it until it becomes important.
611 if (!Parent) {
612 continue;
613 }
614 Parent = Parent->getDefinition();
615 for (CXXRecordDecl::method_iterator M = Parent->method_begin();
616 M != Parent->method_end(); ++M) {
617 if (hasCustomAnnotation(*M, "moz_must_override"))
618 MustOverrides.push_back(*M);
619 }
620 }
621
622 for (OverridesVector::iterator It = MustOverrides.begin();
623 It != MustOverrides.end(); ++It) {
624 bool Overridden = false;
625 for (CXXRecordDecl::method_iterator M = D->method_begin();
626 !Overridden && M != D->method_end(); ++M) {
627 // The way that Clang checks if a method M overrides its parent method
628 // is if the method has the same name but would not overload.
629 if (getNameChecked(M) == getNameChecked(*It) &&
630 !CI.getSema().IsOverload(*M, (*It), false)) {
631 Overridden = true;
632 break;
633 }
634 }
635 if (!Overridden) {
636 unsigned OverrideID = Diag.getDiagnosticIDs()->getCustomDiagID(
637 DiagnosticIDs::Error, "%0 must override %1");
638 unsigned OverrideNote = Diag.getDiagnosticIDs()->getCustomDiagID(
639 DiagnosticIDs::Note, "function to override is here");
640 Diag.Report(D->getLocation(), OverrideID) << D->getDeclName()
641 << (*It)->getDeclName();
642 Diag.Report((*It)->getLocation(), OverrideNote);
643 }
644 }
645
646 return true;
647 }
648
VisitSwitchCase(SwitchCase * Statement)649 bool VisitSwitchCase(SwitchCase *Statement) {
650 handleUnusedExprResult(Statement->getSubStmt());
651 return true;
652 }
VisitCompoundStmt(CompoundStmt * Statement)653 bool VisitCompoundStmt(CompoundStmt *Statement) {
654 for (CompoundStmt::body_iterator It = Statement->body_begin(),
655 E = Statement->body_end();
656 It != E; ++It) {
657 handleUnusedExprResult(*It);
658 }
659 return true;
660 }
VisitIfStmt(IfStmt * Statement)661 bool VisitIfStmt(IfStmt *Statement) {
662 handleUnusedExprResult(Statement->getThen());
663 handleUnusedExprResult(Statement->getElse());
664 return true;
665 }
VisitWhileStmt(WhileStmt * Statement)666 bool VisitWhileStmt(WhileStmt *Statement) {
667 handleUnusedExprResult(Statement->getBody());
668 return true;
669 }
VisitDoStmt(DoStmt * Statement)670 bool VisitDoStmt(DoStmt *Statement) {
671 handleUnusedExprResult(Statement->getBody());
672 return true;
673 }
VisitForStmt(ForStmt * Statement)674 bool VisitForStmt(ForStmt *Statement) {
675 handleUnusedExprResult(Statement->getBody());
676 handleUnusedExprResult(Statement->getInit());
677 handleUnusedExprResult(Statement->getInc());
678 return true;
679 }
VisitBinComma(BinaryOperator * Op)680 bool VisitBinComma(BinaryOperator *Op) {
681 handleUnusedExprResult(Op->getLHS());
682 return true;
683 }
684 };
685
686 /// A cached data of whether classes are refcounted or not.
687 typedef DenseMap<const CXXRecordDecl *, std::pair<const Decl *, bool>>
688 RefCountedMap;
689 RefCountedMap RefCountedClasses;
690
classHasAddRefRelease(const CXXRecordDecl * D)691 bool classHasAddRefRelease(const CXXRecordDecl *D) {
692 const RefCountedMap::iterator &It = RefCountedClasses.find(D);
693 if (It != RefCountedClasses.end()) {
694 return It->second.second;
695 }
696
697 bool SeenAddRef = false;
698 bool SeenRelease = false;
699 for (CXXRecordDecl::method_iterator Method = D->method_begin();
700 Method != D->method_end(); ++Method) {
701 const auto &Name = getNameChecked(Method);
702 if (Name == "AddRef") {
703 SeenAddRef = true;
704 } else if (Name == "Release") {
705 SeenRelease = true;
706 }
707 }
708 RefCountedClasses[D] = std::make_pair(D, SeenAddRef && SeenRelease);
709 return SeenAddRef && SeenRelease;
710 }
711
712 bool isClassRefCounted(QualType T);
713
isClassRefCounted(const CXXRecordDecl * D)714 bool isClassRefCounted(const CXXRecordDecl *D) {
715 // Normalize so that D points to the definition if it exists.
716 if (!D->hasDefinition())
717 return false;
718 D = D->getDefinition();
719 // Base class: anyone with AddRef/Release is obviously a refcounted class.
720 if (classHasAddRefRelease(D))
721 return true;
722
723 // Look through all base cases to figure out if the parent is a refcounted
724 // class.
725 for (CXXRecordDecl::base_class_const_iterator Base = D->bases_begin();
726 Base != D->bases_end(); ++Base) {
727 bool Super = isClassRefCounted(Base->getType());
728 if (Super) {
729 return true;
730 }
731 }
732
733 return false;
734 }
735
isClassRefCounted(QualType T)736 bool isClassRefCounted(QualType T) {
737 while (const clang::ArrayType *ArrTy = T->getAsArrayTypeUnsafe())
738 T = ArrTy->getElementType();
739 CXXRecordDecl *Clazz = T->getAsCXXRecordDecl();
740 return Clazz ? isClassRefCounted(Clazz) : false;
741 }
742
ASTIsInSystemHeader(const ASTContext & AC,const T & D)743 template <class T> bool ASTIsInSystemHeader(const ASTContext &AC, const T &D) {
744 auto &SourceManager = AC.getSourceManager();
745 auto ExpansionLoc = SourceManager.getExpansionLoc(D.getLocStart());
746 if (ExpansionLoc.isInvalid()) {
747 return false;
748 }
749 return SourceManager.isInSystemHeader(ExpansionLoc);
750 }
751
getClassRefCntMember(const CXXRecordDecl * D)752 const FieldDecl *getClassRefCntMember(const CXXRecordDecl *D) {
753 for (RecordDecl::field_iterator Field = D->field_begin(), E = D->field_end();
754 Field != E; ++Field) {
755 if (getNameChecked(Field) == "mRefCnt") {
756 return *Field;
757 }
758 }
759 return 0;
760 }
761
762 const FieldDecl *getBaseRefCntMember(QualType T);
763
getBaseRefCntMember(const CXXRecordDecl * D)764 const FieldDecl *getBaseRefCntMember(const CXXRecordDecl *D) {
765 const FieldDecl *RefCntMember = getClassRefCntMember(D);
766 if (RefCntMember && isClassRefCounted(D)) {
767 return RefCntMember;
768 }
769
770 for (CXXRecordDecl::base_class_const_iterator Base = D->bases_begin(),
771 E = D->bases_end();
772 Base != E; ++Base) {
773 RefCntMember = getBaseRefCntMember(Base->getType());
774 if (RefCntMember) {
775 return RefCntMember;
776 }
777 }
778 return 0;
779 }
780
getBaseRefCntMember(QualType T)781 const FieldDecl *getBaseRefCntMember(QualType T) {
782 while (const clang::ArrayType *ArrTy = T->getAsArrayTypeUnsafe())
783 T = ArrTy->getElementType();
784 CXXRecordDecl *Clazz = T->getAsCXXRecordDecl();
785 return Clazz ? getBaseRefCntMember(Clazz) : 0;
786 }
787
typeHasVTable(QualType T)788 bool typeHasVTable(QualType T) {
789 while (const clang::ArrayType *ArrTy = T->getAsArrayTypeUnsafe())
790 T = ArrTy->getElementType();
791 CXXRecordDecl *Offender = T->getAsCXXRecordDecl();
792 return Offender && Offender->hasDefinition() && Offender->isDynamicClass();
793 }
794 }
795
796 namespace clang {
797 namespace ast_matchers {
798
799 /// This matcher will match any function declaration that is declared as a heap
800 /// allocator.
AST_MATCHER(FunctionDecl,heapAllocator)801 AST_MATCHER(FunctionDecl, heapAllocator) {
802 return MozChecker::hasCustomAnnotation(&Node, "moz_heap_allocator");
803 }
804
805 /// This matcher will match any declaration that is marked as not accepting
806 /// arithmetic expressions in its arguments.
AST_MATCHER(Decl,noArithmeticExprInArgs)807 AST_MATCHER(Decl, noArithmeticExprInArgs) {
808 return MozChecker::hasCustomAnnotation(&Node, "moz_no_arith_expr_in_arg");
809 }
810
811 /// This matcher will match any C++ class that is marked as having a trivial
812 /// constructor and destructor.
AST_MATCHER(CXXRecordDecl,hasTrivialCtorDtor)813 AST_MATCHER(CXXRecordDecl, hasTrivialCtorDtor) {
814 return MozChecker::hasCustomAnnotation(&Node, "moz_trivial_ctor_dtor");
815 }
816
817 /// This matcher will match any function declaration that is marked to prohibit
818 /// calling AddRef or Release on its return value.
AST_MATCHER(FunctionDecl,hasNoAddRefReleaseOnReturnAttr)819 AST_MATCHER(FunctionDecl, hasNoAddRefReleaseOnReturnAttr) {
820 return MozChecker::hasCustomAnnotation(&Node,
821 "moz_no_addref_release_on_return");
822 }
823
824 /// This matcher will match all arithmetic binary operators.
AST_MATCHER(BinaryOperator,binaryArithmeticOperator)825 AST_MATCHER(BinaryOperator, binaryArithmeticOperator) {
826 BinaryOperatorKind OpCode = Node.getOpcode();
827 return OpCode == BO_Mul || OpCode == BO_Div || OpCode == BO_Rem ||
828 OpCode == BO_Add || OpCode == BO_Sub || OpCode == BO_Shl ||
829 OpCode == BO_Shr || OpCode == BO_And || OpCode == BO_Xor ||
830 OpCode == BO_Or || OpCode == BO_MulAssign || OpCode == BO_DivAssign ||
831 OpCode == BO_RemAssign || OpCode == BO_AddAssign ||
832 OpCode == BO_SubAssign || OpCode == BO_ShlAssign ||
833 OpCode == BO_ShrAssign || OpCode == BO_AndAssign ||
834 OpCode == BO_XorAssign || OpCode == BO_OrAssign;
835 }
836
837 /// This matcher will match all arithmetic unary operators.
AST_MATCHER(UnaryOperator,unaryArithmeticOperator)838 AST_MATCHER(UnaryOperator, unaryArithmeticOperator) {
839 UnaryOperatorKind OpCode = Node.getOpcode();
840 return OpCode == UO_PostInc || OpCode == UO_PostDec || OpCode == UO_PreInc ||
841 OpCode == UO_PreDec || OpCode == UO_Plus || OpCode == UO_Minus ||
842 OpCode == UO_Not;
843 }
844
845 /// This matcher will match == and != binary operators.
AST_MATCHER(BinaryOperator,binaryEqualityOperator)846 AST_MATCHER(BinaryOperator, binaryEqualityOperator) {
847 BinaryOperatorKind OpCode = Node.getOpcode();
848 return OpCode == BO_EQ || OpCode == BO_NE;
849 }
850
851 /// This matcher will match floating point types.
AST_MATCHER(QualType,isFloat)852 AST_MATCHER(QualType, isFloat) { return Node->isRealFloatingType(); }
853
854 /// This matcher will match locations in system headers. This is adopted from
855 /// isExpansionInSystemHeader in newer clangs, but modified in order to work
856 /// with old clangs that we use on infra.
AST_MATCHER(BinaryOperator,isInSystemHeader)857 AST_MATCHER(BinaryOperator, isInSystemHeader) {
858 return ASTIsInSystemHeader(Finder->getASTContext(), Node);
859 }
860
861 /// This matcher will match a list of files. These files contain
862 /// known NaN-testing expressions which we would like to whitelist.
AST_MATCHER(BinaryOperator,isInWhitelistForNaNExpr)863 AST_MATCHER(BinaryOperator, isInWhitelistForNaNExpr) {
864 const char* whitelist[] = {
865 "SkScalar.h",
866 "json_writer.cpp"
867 };
868
869 SourceLocation Loc = Node.getOperatorLoc();
870 auto &SourceManager = Finder->getASTContext().getSourceManager();
871 SmallString<1024> FileName = SourceManager.getFilename(Loc);
872
873 for (auto itr = std::begin(whitelist); itr != std::end(whitelist); itr++) {
874 if (llvm::sys::path::rbegin(FileName)->equals(*itr)) {
875 return true;
876 }
877 }
878
879 return false;
880 }
881
882 /// This matcher will match all accesses to AddRef or Release methods.
AST_MATCHER(MemberExpr,isAddRefOrRelease)883 AST_MATCHER(MemberExpr, isAddRefOrRelease) {
884 ValueDecl *Member = Node.getMemberDecl();
885 CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member);
886 if (Method) {
887 const auto &Name = getNameChecked(Method);
888 return Name == "AddRef" || Name == "Release";
889 }
890 return false;
891 }
892
893 /// This matcher will select classes which are refcounted.
AST_MATCHER(CXXRecordDecl,hasRefCntMember)894 AST_MATCHER(CXXRecordDecl, hasRefCntMember) {
895 return isClassRefCounted(&Node) && getClassRefCntMember(&Node);
896 }
897
AST_MATCHER(QualType,hasVTable)898 AST_MATCHER(QualType, hasVTable) { return typeHasVTable(Node); }
899
AST_MATCHER(CXXRecordDecl,hasNeedsNoVTableTypeAttr)900 AST_MATCHER(CXXRecordDecl, hasNeedsNoVTableTypeAttr) {
901 return MozChecker::hasCustomAnnotation(&Node, "moz_needs_no_vtable_type");
902 }
903
904 /// This matcher will select classes which are non-memmovable
AST_MATCHER(QualType,isNonMemMovable)905 AST_MATCHER(QualType, isNonMemMovable) {
906 return NonMemMovable.hasEffectiveAnnotation(Node);
907 }
908
909 /// This matcher will select classes which require a memmovable template arg
AST_MATCHER(CXXRecordDecl,needsMemMovableTemplateArg)910 AST_MATCHER(CXXRecordDecl, needsMemMovableTemplateArg) {
911 return MozChecker::hasCustomAnnotation(&Node, "moz_needs_memmovable_type");
912 }
913
914 /// This matcher will select classes which require all members to be memmovable
AST_MATCHER(CXXRecordDecl,needsMemMovableMembers)915 AST_MATCHER(CXXRecordDecl, needsMemMovableMembers) {
916 return MozChecker::hasCustomAnnotation(&Node, "moz_needs_memmovable_members");
917 }
918
AST_MATCHER(CXXConstructorDecl,isInterestingImplicitCtor)919 AST_MATCHER(CXXConstructorDecl, isInterestingImplicitCtor) {
920 const CXXConstructorDecl *Declaration = Node.getCanonicalDecl();
921 return
922 // Skip ignored namespaces and paths
923 !isInIgnoredNamespaceForImplicitCtor(Declaration) &&
924 !isIgnoredPathForImplicitCtor(Declaration) &&
925 // We only want Converting constructors
926 Declaration->isConvertingConstructor(false) &&
927 // We don't want copy of move constructors, as those are allowed to be
928 // implicit
929 !Declaration->isCopyOrMoveConstructor() &&
930 // We don't want deleted constructors.
931 !Declaration->isDeleted();
932 }
933
934 // We can't call this "isImplicit" since it clashes with an existing matcher in
935 // clang.
AST_MATCHER(CXXConstructorDecl,isMarkedImplicit)936 AST_MATCHER(CXXConstructorDecl, isMarkedImplicit) {
937 return MozChecker::hasCustomAnnotation(&Node, "moz_implicit");
938 }
939
AST_MATCHER(CXXRecordDecl,isConcreteClass)940 AST_MATCHER(CXXRecordDecl, isConcreteClass) { return !Node.isAbstract(); }
941
AST_MATCHER(QualType,autoNonAutoableType)942 AST_MATCHER(QualType, autoNonAutoableType) {
943 if (const AutoType *T = Node->getContainedAutoType()) {
944 if (const CXXRecordDecl *Rec = T->getAsCXXRecordDecl()) {
945 return MozChecker::hasCustomAnnotation(Rec, "moz_non_autoable");
946 }
947 }
948 return false;
949 }
950
AST_MATCHER(CXXConstructorDecl,isExplicitMoveConstructor)951 AST_MATCHER(CXXConstructorDecl, isExplicitMoveConstructor) {
952 return Node.isExplicit() && Node.isMoveConstructor();
953 }
954
AST_MATCHER(CXXConstructorDecl,isCompilerProvidedCopyConstructor)955 AST_MATCHER(CXXConstructorDecl, isCompilerProvidedCopyConstructor) {
956 return !Node.isUserProvided() && Node.isCopyConstructor();
957 }
958
AST_MATCHER(CallExpr,isAssertAssignmentTestFunc)959 AST_MATCHER(CallExpr, isAssertAssignmentTestFunc) {
960 static const std::string AssertName = "MOZ_AssertAssignmentTest";
961 const FunctionDecl *Method = Node.getDirectCallee();
962
963 return Method
964 && Method->getDeclName().isIdentifier()
965 && Method->getName() == AssertName;
966 }
967
AST_MATCHER(CallExpr,isSnprintfLikeFunc)968 AST_MATCHER(CallExpr, isSnprintfLikeFunc) {
969 static const std::string Snprintf = "snprintf";
970 static const std::string Vsnprintf = "vsnprintf";
971 const FunctionDecl *Func = Node.getDirectCallee();
972
973 if (!Func || isa<CXXMethodDecl>(Func)) {
974 return false;
975 }
976
977 StringRef Name = getNameChecked(Func);
978 if (Name != Snprintf && Name != Vsnprintf) {
979 return false;
980 }
981
982 return !isIgnoredPathForSprintfLiteral(&Node, Finder->getASTContext().getSourceManager());
983 }
984
AST_MATCHER(CXXRecordDecl,isLambdaDecl)985 AST_MATCHER(CXXRecordDecl, isLambdaDecl) {
986 return Node.isLambda();
987 }
988
AST_MATCHER(QualType,isRefPtr)989 AST_MATCHER(QualType, isRefPtr) {
990 return typeIsRefPtr(Node);
991 }
992
AST_MATCHER(CXXRecordDecl,hasBaseClasses)993 AST_MATCHER(CXXRecordDecl, hasBaseClasses) {
994 const CXXRecordDecl *Decl = Node.getCanonicalDecl();
995
996 // Must have definition and should inherit other classes
997 return Decl && Decl->hasDefinition() && Decl->getNumBases();
998 }
999
AST_MATCHER(CXXMethodDecl,isRequiredBaseMethod)1000 AST_MATCHER(CXXMethodDecl, isRequiredBaseMethod) {
1001 const CXXMethodDecl *Decl = Node.getCanonicalDecl();
1002 return Decl
1003 && MozChecker::hasCustomAnnotation(Decl, "moz_required_base_method");
1004 }
1005
AST_MATCHER(CXXMethodDecl,isNonVirtual)1006 AST_MATCHER(CXXMethodDecl, isNonVirtual) {
1007 const CXXMethodDecl *Decl = Node.getCanonicalDecl();
1008 return Decl && !Decl->isVirtual();
1009 }
1010 }
1011 }
1012
1013 namespace {
1014
dumpAnnotationReason(DiagnosticsEngine & Diag,QualType T,SourceLocation Loc)1015 void CustomTypeAnnotation::dumpAnnotationReason(DiagnosticsEngine &Diag,
1016 QualType T,
1017 SourceLocation Loc) {
1018 unsigned InheritsID = Diag.getDiagnosticIDs()->getCustomDiagID(
1019 DiagnosticIDs::Note,
1020 "%1 is a %0 type because it inherits from a %0 type %2");
1021 unsigned MemberID = Diag.getDiagnosticIDs()->getCustomDiagID(
1022 DiagnosticIDs::Note, "%1 is a %0 type because member %2 is a %0 type %3");
1023 unsigned ArrayID = Diag.getDiagnosticIDs()->getCustomDiagID(
1024 DiagnosticIDs::Note,
1025 "%1 is a %0 type because it is an array of %0 type %2");
1026 unsigned TemplID = Diag.getDiagnosticIDs()->getCustomDiagID(
1027 DiagnosticIDs::Note,
1028 "%1 is a %0 type because it has a template argument %0 type %2");
1029
1030 AnnotationReason Reason = directAnnotationReason(T);
1031 for (;;) {
1032 switch (Reason.Kind) {
1033 case RK_ArrayElement:
1034 Diag.Report(Loc, ArrayID) << Pretty << T << Reason.Type;
1035 break;
1036 case RK_BaseClass: {
1037 const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl();
1038 assert(Declaration && "This type should be a C++ class");
1039
1040 Diag.Report(Declaration->getLocation(), InheritsID) << Pretty << T
1041 << Reason.Type;
1042 break;
1043 }
1044 case RK_Field:
1045 Diag.Report(Reason.Field->getLocation(), MemberID)
1046 << Pretty << T << Reason.Field << Reason.Type;
1047 break;
1048 case RK_TemplateInherited: {
1049 const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl();
1050 assert(Declaration && "This type should be a C++ class");
1051
1052 Diag.Report(Declaration->getLocation(), TemplID) << Pretty << T
1053 << Reason.Type;
1054 break;
1055 }
1056 default:
1057 // FIXME (bug 1203263): note the original annotation.
1058 return;
1059 }
1060
1061 T = Reason.Type;
1062 Reason = directAnnotationReason(T);
1063 }
1064 }
1065
hasLiteralAnnotation(QualType T) const1066 bool CustomTypeAnnotation::hasLiteralAnnotation(QualType T) const {
1067 #if CLANG_VERSION_FULL >= 306
1068 if (const TagDecl *D = T->getAsTagDecl()) {
1069 #else
1070 if (const CXXRecordDecl *D = T->getAsCXXRecordDecl()) {
1071 #endif
1072 return hasFakeAnnotation(D) || MozChecker::hasCustomAnnotation(D, Spelling);
1073 }
1074 return false;
1075 }
1076
1077 CustomTypeAnnotation::AnnotationReason
1078 CustomTypeAnnotation::directAnnotationReason(QualType T) {
1079 if (hasLiteralAnnotation(T)) {
1080 AnnotationReason Reason = {T, RK_Direct, nullptr};
1081 return Reason;
1082 }
1083
1084 // Check if we have a cached answer
1085 void *Key = T.getAsOpaquePtr();
1086 ReasonCache::iterator Cached = Cache.find(T.getAsOpaquePtr());
1087 if (Cached != Cache.end()) {
1088 return Cached->second;
1089 }
1090
1091 // Check if we have a type which we can recurse into
1092 if (const clang::ArrayType *Array = T->getAsArrayTypeUnsafe()) {
1093 if (hasEffectiveAnnotation(Array->getElementType())) {
1094 AnnotationReason Reason = {Array->getElementType(), RK_ArrayElement,
1095 nullptr};
1096 Cache[Key] = Reason;
1097 return Reason;
1098 }
1099 }
1100
1101 // Recurse into Base classes
1102 if (const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl()) {
1103 if (Declaration->hasDefinition()) {
1104 Declaration = Declaration->getDefinition();
1105
1106 for (const CXXBaseSpecifier &Base : Declaration->bases()) {
1107 if (hasEffectiveAnnotation(Base.getType())) {
1108 AnnotationReason Reason = {Base.getType(), RK_BaseClass, nullptr};
1109 Cache[Key] = Reason;
1110 return Reason;
1111 }
1112 }
1113
1114 // Recurse into members
1115 for (const FieldDecl *Field : Declaration->fields()) {
1116 if (hasEffectiveAnnotation(Field->getType())) {
1117 AnnotationReason Reason = {Field->getType(), RK_Field, Field};
1118 Cache[Key] = Reason;
1119 return Reason;
1120 }
1121 }
1122
1123 // Recurse into template arguments if the annotation
1124 // MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS is present
1125 if (MozChecker::hasCustomAnnotation(
1126 Declaration, "moz_inherit_type_annotations_from_template_args")) {
1127 const ClassTemplateSpecializationDecl *Spec =
1128 dyn_cast<ClassTemplateSpecializationDecl>(Declaration);
1129 if (Spec) {
1130 const TemplateArgumentList &Args = Spec->getTemplateArgs();
1131
1132 AnnotationReason Reason = tmplArgAnnotationReason(Args.asArray());
1133 if (Reason.Kind != RK_None) {
1134 Cache[Key] = Reason;
1135 return Reason;
1136 }
1137 }
1138 }
1139 }
1140 }
1141
1142 AnnotationReason Reason = {QualType(), RK_None, nullptr};
1143 Cache[Key] = Reason;
1144 return Reason;
1145 }
1146
1147 CustomTypeAnnotation::AnnotationReason
1148 CustomTypeAnnotation::tmplArgAnnotationReason(ArrayRef<TemplateArgument> Args) {
1149 for (const TemplateArgument &Arg : Args) {
1150 if (Arg.getKind() == TemplateArgument::Type) {
1151 QualType Type = Arg.getAsType();
1152 if (hasEffectiveAnnotation(Type)) {
1153 AnnotationReason Reason = {Type, RK_TemplateInherited, nullptr};
1154 return Reason;
1155 }
1156 } else if (Arg.getKind() == TemplateArgument::Pack) {
1157 AnnotationReason Reason = tmplArgAnnotationReason(Arg.getPackAsArray());
1158 if (Reason.Kind != RK_None) {
1159 return Reason;
1160 }
1161 }
1162 }
1163
1164 AnnotationReason Reason = {QualType(), RK_None, nullptr};
1165 return Reason;
1166 }
1167
1168 bool isPlacementNew(const CXXNewExpr *Expression) {
1169 // Regular new expressions aren't placement new
1170 if (Expression->getNumPlacementArgs() == 0)
1171 return false;
1172 const FunctionDecl *Declaration = Expression->getOperatorNew();
1173 if (Declaration && MozChecker::hasCustomAnnotation(Declaration,
1174 "moz_heap_allocator")) {
1175 return false;
1176 }
1177 return true;
1178 }
1179
1180 DiagnosticsMatcher::DiagnosticsMatcher() {
1181 AstMatcher.addMatcher(varDecl().bind("node"), &Scope);
1182 AstMatcher.addMatcher(cxxNewExpr().bind("node"), &Scope);
1183 AstMatcher.addMatcher(materializeTemporaryExpr().bind("node"), &Scope);
1184 AstMatcher.addMatcher(
1185 callExpr(callee(functionDecl(heapAllocator()))).bind("node"),
1186 &Scope);
1187 AstMatcher.addMatcher(parmVarDecl().bind("parm_vardecl"), &Scope);
1188
1189 AstMatcher.addMatcher(
1190 callExpr(allOf(hasDeclaration(noArithmeticExprInArgs()),
1191 anyOf(hasDescendant(
1192 binaryOperator(
1193 allOf(binaryArithmeticOperator(),
1194 hasLHS(hasDescendant(declRefExpr())),
1195 hasRHS(hasDescendant(declRefExpr()))))
1196 .bind("node")),
1197 hasDescendant(
1198 unaryOperator(
1199 allOf(unaryArithmeticOperator(),
1200 hasUnaryOperand(allOf(
1201 hasType(builtinType()),
1202 anyOf(hasDescendant(declRefExpr()),
1203 declRefExpr())))))
1204 .bind("node")))))
1205 .bind("call"),
1206 &ArithmeticArg);
1207 AstMatcher.addMatcher(
1208 cxxConstructExpr(
1209 allOf(hasDeclaration(noArithmeticExprInArgs()),
1210 anyOf(hasDescendant(
1211 binaryOperator(
1212 allOf(binaryArithmeticOperator(),
1213 hasLHS(hasDescendant(declRefExpr())),
1214 hasRHS(hasDescendant(declRefExpr()))))
1215 .bind("node")),
1216 hasDescendant(
1217 unaryOperator(
1218 allOf(unaryArithmeticOperator(),
1219 hasUnaryOperand(allOf(
1220 hasType(builtinType()),
1221 anyOf(hasDescendant(declRefExpr()),
1222 declRefExpr())))))
1223 .bind("node")))))
1224 .bind("call"),
1225 &ArithmeticArg);
1226
1227 AstMatcher.addMatcher(cxxRecordDecl(hasTrivialCtorDtor()).bind("node"),
1228 &TrivialCtorDtor);
1229
1230 AstMatcher.addMatcher(
1231 binaryOperator(
1232 allOf(binaryEqualityOperator(),
1233 hasLHS(hasIgnoringParenImpCasts(
1234 declRefExpr(hasType(qualType((isFloat())))).bind("lhs"))),
1235 hasRHS(hasIgnoringParenImpCasts(
1236 declRefExpr(hasType(qualType((isFloat())))).bind("rhs"))),
1237 unless(anyOf(isInSystemHeader(), isInWhitelistForNaNExpr()))))
1238 .bind("node"),
1239 &NaNExpr);
1240
1241 // First, look for direct parents of the MemberExpr.
1242 AstMatcher.addMatcher(
1243 callExpr(
1244 callee(functionDecl(hasNoAddRefReleaseOnReturnAttr()).bind("func")),
1245 hasParent(memberExpr(isAddRefOrRelease(), hasParent(callExpr()))
1246 .bind("member")))
1247 .bind("node"),
1248 &NoAddRefReleaseOnReturn);
1249 // Then, look for MemberExpr that need to be casted to the right type using
1250 // an intermediary CastExpr before we get to the CallExpr.
1251 AstMatcher.addMatcher(
1252 callExpr(
1253 callee(functionDecl(hasNoAddRefReleaseOnReturnAttr()).bind("func")),
1254 hasParent(castExpr(
1255 hasParent(memberExpr(isAddRefOrRelease(), hasParent(callExpr()))
1256 .bind("member")))))
1257 .bind("node"),
1258 &NoAddRefReleaseOnReturn);
1259
1260 // We want to reject any code which captures a pointer to an object of a
1261 // refcounted type, and then lets that value escape. As a primitive analysis,
1262 // we reject any occurances of the lambda as a template parameter to a class
1263 // (which could allow it to escape), as well as any presence of such a lambda
1264 // in a return value (either from lambdas, or in c++14, auto functions).
1265 //
1266 // We check these lambdas' capture lists for raw pointers to refcounted types.
1267 AstMatcher.addMatcher(
1268 functionDecl(returns(recordType(hasDeclaration(cxxRecordDecl(
1269 isLambdaDecl()).bind("decl"))))),
1270 &RefCountedInsideLambda);
1271 AstMatcher.addMatcher(lambdaExpr().bind("lambdaExpr"),
1272 &RefCountedInsideLambda);
1273 AstMatcher.addMatcher(
1274 classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType(
1275 recordType(hasDeclaration(cxxRecordDecl(
1276 isLambdaDecl()).bind("decl")))))),
1277 &RefCountedInsideLambda);
1278
1279 // Older clang versions such as the ones used on the infra recognize these
1280 // conversions as 'operator _Bool', but newer clang versions recognize these
1281 // as 'operator bool'.
1282 AstMatcher.addMatcher(
1283 cxxMethodDecl(anyOf(hasName("operator bool"), hasName("operator _Bool")))
1284 .bind("node"),
1285 &ExplicitOperatorBool);
1286
1287 AstMatcher.addMatcher(cxxRecordDecl().bind("decl"), &NoDuplicateRefCntMember);
1288
1289 AstMatcher.addMatcher(
1290 classTemplateSpecializationDecl(
1291 allOf(hasAnyTemplateArgument(refersToType(hasVTable())),
1292 hasNeedsNoVTableTypeAttr()))
1293 .bind("node"),
1294 &NeedsNoVTableType);
1295
1296 // Handle non-mem-movable template specializations
1297 AstMatcher.addMatcher(
1298 classTemplateSpecializationDecl(
1299 allOf(needsMemMovableTemplateArg(),
1300 hasAnyTemplateArgument(refersToType(isNonMemMovable()))))
1301 .bind("specialization"),
1302 &NonMemMovableTemplateArg);
1303
1304 // Handle non-mem-movable members
1305 AstMatcher.addMatcher(
1306 cxxRecordDecl(needsMemMovableMembers())
1307 .bind("decl"),
1308 &NonMemMovableMember);
1309
1310 AstMatcher.addMatcher(cxxConstructorDecl(isInterestingImplicitCtor(),
1311 ofClass(allOf(isConcreteClass(),
1312 decl().bind("class"))),
1313 unless(isMarkedImplicit()))
1314 .bind("ctor"),
1315 &ExplicitImplicit);
1316
1317 AstMatcher.addMatcher(varDecl(hasType(autoNonAutoableType())).bind("node"),
1318 &NoAutoType);
1319
1320 AstMatcher.addMatcher(
1321 cxxConstructorDecl(isExplicitMoveConstructor()).bind("node"),
1322 &NoExplicitMoveConstructor);
1323
1324 AstMatcher.addMatcher(
1325 cxxConstructExpr(
1326 hasDeclaration(cxxConstructorDecl(isCompilerProvidedCopyConstructor(),
1327 ofClass(hasRefCntMember()))))
1328 .bind("node"),
1329 &RefCountedCopyConstructor);
1330
1331 AstMatcher.addMatcher(
1332 callExpr(isAssertAssignmentTestFunc()).bind("funcCall"),
1333 &AssertAttribution);
1334
1335 AstMatcher.addMatcher(varDecl(hasType(isRefPtr())).bind("decl"),
1336 &KungFuDeathGrip);
1337
1338 AstMatcher.addMatcher(
1339 callExpr(isSnprintfLikeFunc(),
1340 allOf(hasArgument(0, ignoringParenImpCasts(declRefExpr().bind("buffer"))),
1341 anyOf(hasArgument(1, sizeOfExpr(hasIgnoringParenImpCasts(declRefExpr().bind("size")))),
1342 hasArgument(1, integerLiteral().bind("immediate")),
1343 hasArgument(1, declRefExpr(to(varDecl(hasType(isConstQualified()),
1344 hasInitializer(integerLiteral().bind("constant")))))))))
1345 .bind("funcCall"),
1346 &SprintfLiteral
1347 );
1348
1349 AstMatcher.addMatcher(cxxRecordDecl(hasBaseClasses()).bind("class"),
1350 &OverrideBaseCall);
1351
1352 AstMatcher.addMatcher(
1353 cxxMethodDecl(isNonVirtual(), isRequiredBaseMethod()).bind("method"),
1354 &OverrideBaseCallUsage);
1355
1356 AstMatcher.addMatcher(
1357 functionDecl(anyOf(allOf(isDefinition(),
1358 hasAncestor(classTemplateSpecializationDecl()
1359 .bind("spec"))),
1360 isDefinition()))
1361 .bind("func"),
1362 &NonParamInsideFunctionDecl);
1363 AstMatcher.addMatcher(
1364 lambdaExpr().bind("lambda"),
1365 &NonParamInsideFunctionDecl);
1366 }
1367
1368 // These enum variants determine whether an allocation has occured in the code.
1369 enum AllocationVariety {
1370 AV_None,
1371 AV_Global,
1372 AV_Automatic,
1373 AV_Temporary,
1374 AV_Heap,
1375 };
1376
1377 // XXX Currently the Decl* in the AutomaticTemporaryMap is unused, but it
1378 // probably will be used at some point in the future, in order to produce better
1379 // error messages.
1380 typedef DenseMap<const MaterializeTemporaryExpr *, const Decl *>
1381 AutomaticTemporaryMap;
1382 AutomaticTemporaryMap AutomaticTemporaries;
1383
1384 void DiagnosticsMatcher::ScopeChecker::run(
1385 const MatchFinder::MatchResult &Result) {
1386 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
1387
1388 // There are a variety of different reasons why something could be allocated
1389 AllocationVariety Variety = AV_None;
1390 SourceLocation Loc;
1391 QualType T;
1392
1393 if (const ParmVarDecl *D =
1394 Result.Nodes.getNodeAs<ParmVarDecl>("parm_vardecl")) {
1395 if (D->hasUnparsedDefaultArg() || D->hasUninstantiatedDefaultArg()) {
1396 return;
1397 }
1398 if (const Expr *Default = D->getDefaultArg()) {
1399 if (const MaterializeTemporaryExpr *E =
1400 dyn_cast<MaterializeTemporaryExpr>(Default)) {
1401 // We have just found a ParmVarDecl which has, as its default argument,
1402 // a MaterializeTemporaryExpr. We mark that MaterializeTemporaryExpr as
1403 // automatic, by adding it to the AutomaticTemporaryMap.
1404 // Reporting on this type will occur when the MaterializeTemporaryExpr
1405 // is matched against.
1406 AutomaticTemporaries[E] = D;
1407 }
1408 }
1409 return;
1410 }
1411
1412 // Determine the type of allocation which we detected
1413 if (const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>("node")) {
1414 if (D->hasGlobalStorage()) {
1415 Variety = AV_Global;
1416 } else {
1417 Variety = AV_Automatic;
1418 }
1419 T = D->getType();
1420 Loc = D->getLocStart();
1421 } else if (const CXXNewExpr *E = Result.Nodes.getNodeAs<CXXNewExpr>("node")) {
1422 // New allocates things on the heap.
1423 // We don't consider placement new to do anything, as it doesn't actually
1424 // allocate the storage, and thus gives us no useful information.
1425 if (!isPlacementNew(E)) {
1426 Variety = AV_Heap;
1427 T = E->getAllocatedType();
1428 Loc = E->getLocStart();
1429 }
1430 } else if (const MaterializeTemporaryExpr *E =
1431 Result.Nodes.getNodeAs<MaterializeTemporaryExpr>("node")) {
1432 // Temporaries can actually have varying storage durations, due to temporary
1433 // lifetime extension. We consider the allocation variety of this temporary
1434 // to be the same as the allocation variety of its lifetime.
1435
1436 // XXX We maybe should mark these lifetimes as being due to a temporary
1437 // which has had its lifetime extended, to improve the error messages.
1438 switch (E->getStorageDuration()) {
1439 case SD_FullExpression: {
1440 // Check if this temporary is allocated as a default argument!
1441 // if it is, we want to pretend that it is automatic.
1442 AutomaticTemporaryMap::iterator AutomaticTemporary =
1443 AutomaticTemporaries.find(E);
1444 if (AutomaticTemporary != AutomaticTemporaries.end()) {
1445 Variety = AV_Automatic;
1446 } else {
1447 Variety = AV_Temporary;
1448 }
1449 } break;
1450 case SD_Automatic:
1451 Variety = AV_Automatic;
1452 break;
1453 case SD_Thread:
1454 case SD_Static:
1455 Variety = AV_Global;
1456 break;
1457 case SD_Dynamic:
1458 assert(false && "I don't think that this ever should occur...");
1459 Variety = AV_Heap;
1460 break;
1461 }
1462 T = E->getType().getUnqualifiedType();
1463 Loc = E->getLocStart();
1464 } else if (const CallExpr *E = Result.Nodes.getNodeAs<CallExpr>("node")) {
1465 T = E->getType()->getPointeeType();
1466 if (!T.isNull()) {
1467 // This will always allocate on the heap, as the heapAllocator() check
1468 // was made in the matcher
1469 Variety = AV_Heap;
1470 Loc = E->getLocStart();
1471 }
1472 }
1473
1474 // Error messages for incorrect allocations.
1475 unsigned StackID = Diag.getDiagnosticIDs()->getCustomDiagID(
1476 DiagnosticIDs::Error, "variable of type %0 only valid on the stack");
1477 unsigned GlobalID = Diag.getDiagnosticIDs()->getCustomDiagID(
1478 DiagnosticIDs::Error, "variable of type %0 only valid as global");
1479 unsigned HeapID = Diag.getDiagnosticIDs()->getCustomDiagID(
1480 DiagnosticIDs::Error, "variable of type %0 only valid on the heap");
1481 unsigned NonHeapID = Diag.getDiagnosticIDs()->getCustomDiagID(
1482 DiagnosticIDs::Error, "variable of type %0 is not valid on the heap");
1483 unsigned NonTemporaryID = Diag.getDiagnosticIDs()->getCustomDiagID(
1484 DiagnosticIDs::Error, "variable of type %0 is not valid in a temporary");
1485
1486 unsigned StackNoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
1487 DiagnosticIDs::Note,
1488 "value incorrectly allocated in an automatic variable");
1489 unsigned GlobalNoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
1490 DiagnosticIDs::Note, "value incorrectly allocated in a global variable");
1491 unsigned HeapNoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
1492 DiagnosticIDs::Note, "value incorrectly allocated on the heap");
1493 unsigned TemporaryNoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
1494 DiagnosticIDs::Note, "value incorrectly allocated in a temporary");
1495
1496 // Report errors depending on the annotations on the input types.
1497 switch (Variety) {
1498 case AV_None:
1499 return;
1500
1501 case AV_Global:
1502 StackClass.reportErrorIfPresent(Diag, T, Loc, StackID, GlobalNoteID);
1503 HeapClass.reportErrorIfPresent(Diag, T, Loc, HeapID, GlobalNoteID);
1504 break;
1505
1506 case AV_Automatic:
1507 GlobalClass.reportErrorIfPresent(Diag, T, Loc, GlobalID, StackNoteID);
1508 HeapClass.reportErrorIfPresent(Diag, T, Loc, HeapID, StackNoteID);
1509 break;
1510
1511 case AV_Temporary:
1512 GlobalClass.reportErrorIfPresent(Diag, T, Loc, GlobalID, TemporaryNoteID);
1513 HeapClass.reportErrorIfPresent(Diag, T, Loc, HeapID, TemporaryNoteID);
1514 NonTemporaryClass.reportErrorIfPresent(Diag, T, Loc, NonTemporaryID,
1515 TemporaryNoteID);
1516 break;
1517
1518 case AV_Heap:
1519 GlobalClass.reportErrorIfPresent(Diag, T, Loc, GlobalID, HeapNoteID);
1520 StackClass.reportErrorIfPresent(Diag, T, Loc, StackID, HeapNoteID);
1521 NonHeapClass.reportErrorIfPresent(Diag, T, Loc, NonHeapID, HeapNoteID);
1522 break;
1523 }
1524 }
1525
1526 void DiagnosticsMatcher::ArithmeticArgChecker::run(
1527 const MatchFinder::MatchResult &Result) {
1528 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
1529 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
1530 DiagnosticIDs::Error,
1531 "cannot pass an arithmetic expression of built-in types to %0");
1532 const Expr *Expression = Result.Nodes.getNodeAs<Expr>("node");
1533 if (const CallExpr *Call = Result.Nodes.getNodeAs<CallExpr>("call")) {
1534 Diag.Report(Expression->getLocStart(), ErrorID) << Call->getDirectCallee();
1535 } else if (const CXXConstructExpr *Ctr =
1536 Result.Nodes.getNodeAs<CXXConstructExpr>("call")) {
1537 Diag.Report(Expression->getLocStart(), ErrorID) << Ctr->getConstructor();
1538 }
1539 }
1540
1541 void DiagnosticsMatcher::TrivialCtorDtorChecker::run(
1542 const MatchFinder::MatchResult &Result) {
1543 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
1544 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
1545 DiagnosticIDs::Error,
1546 "class %0 must have trivial constructors and destructors");
1547 const CXXRecordDecl *Node = Result.Nodes.getNodeAs<CXXRecordDecl>("node");
1548
1549 // We need to accept non-constexpr trivial constructors as well. This occurs
1550 // when a struct contains pod members, which will not be initialized. As
1551 // constexpr values are initialized, the constructor is non-constexpr.
1552 bool BadCtor = !(Node->hasConstexprDefaultConstructor() ||
1553 Node->hasTrivialDefaultConstructor());
1554 bool BadDtor = !Node->hasTrivialDestructor();
1555 if (BadCtor || BadDtor)
1556 Diag.Report(Node->getLocStart(), ErrorID) << Node;
1557 }
1558
1559 void DiagnosticsMatcher::NaNExprChecker::run(
1560 const MatchFinder::MatchResult &Result) {
1561 if (!Result.Context->getLangOpts().CPlusPlus) {
1562 // mozilla::IsNaN is not usable in C, so there is no point in issuing these
1563 // warnings.
1564 return;
1565 }
1566
1567 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
1568 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
1569 DiagnosticIDs::Error, "comparing a floating point value to itself for "
1570 "NaN checking can lead to incorrect results");
1571 unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
1572 DiagnosticIDs::Note, "consider using mozilla::IsNaN instead");
1573 const BinaryOperator *Expression = Result.Nodes.getNodeAs<BinaryOperator>(
1574 "node");
1575 const DeclRefExpr *LHS = Result.Nodes.getNodeAs<DeclRefExpr>("lhs");
1576 const DeclRefExpr *RHS = Result.Nodes.getNodeAs<DeclRefExpr>("rhs");
1577 const ImplicitCastExpr *LHSExpr = dyn_cast<ImplicitCastExpr>(
1578 Expression->getLHS());
1579 const ImplicitCastExpr *RHSExpr = dyn_cast<ImplicitCastExpr>(
1580 Expression->getRHS());
1581 // The AST subtree that we are looking for will look like this:
1582 // -BinaryOperator ==/!=
1583 // |-ImplicitCastExpr LValueToRValue
1584 // | |-DeclRefExpr
1585 // |-ImplicitCastExpr LValueToRValue
1586 // |-DeclRefExpr
1587 // The check below ensures that we are dealing with the correct AST subtree
1588 // shape, and
1589 // also that both of the found DeclRefExpr's point to the same declaration.
1590 if (LHS->getFoundDecl() == RHS->getFoundDecl() && LHSExpr && RHSExpr &&
1591 std::distance(LHSExpr->child_begin(), LHSExpr->child_end()) == 1 &&
1592 std::distance(RHSExpr->child_begin(), RHSExpr->child_end()) == 1 &&
1593 *LHSExpr->child_begin() == LHS && *RHSExpr->child_begin() == RHS) {
1594 Diag.Report(Expression->getLocStart(), ErrorID);
1595 Diag.Report(Expression->getLocStart(), NoteID);
1596 }
1597 }
1598
1599 void DiagnosticsMatcher::NoAddRefReleaseOnReturnChecker::run(
1600 const MatchFinder::MatchResult &Result) {
1601 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
1602 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
1603 DiagnosticIDs::Error, "%1 cannot be called on the return value of %0");
1604 const Stmt *Node = Result.Nodes.getNodeAs<Stmt>("node");
1605 const FunctionDecl *Func = Result.Nodes.getNodeAs<FunctionDecl>("func");
1606 const MemberExpr *Member = Result.Nodes.getNodeAs<MemberExpr>("member");
1607 const CXXMethodDecl *Method =
1608 dyn_cast<CXXMethodDecl>(Member->getMemberDecl());
1609
1610 Diag.Report(Node->getLocStart(), ErrorID) << Func << Method;
1611 }
1612
1613 void DiagnosticsMatcher::RefCountedInsideLambdaChecker::run(
1614 const MatchFinder::MatchResult &Result) {
1615 Context = Result.Context;
1616 static DenseSet<const CXXRecordDecl*> CheckedDecls;
1617
1618 const CXXRecordDecl *Lambda = Result.Nodes.getNodeAs<CXXRecordDecl>("decl");
1619
1620 if (const LambdaExpr *OuterLambda =
1621 Result.Nodes.getNodeAs<LambdaExpr>("lambdaExpr")) {
1622 const CXXMethodDecl *OpCall = OuterLambda->getCallOperator();
1623 QualType ReturnTy = OpCall->getReturnType();
1624 if (const CXXRecordDecl *Record = ReturnTy->getAsCXXRecordDecl()) {
1625 Lambda = Record;
1626 }
1627 }
1628
1629 if (!Lambda || !Lambda->isLambda()) {
1630 return;
1631 }
1632
1633 // Don't report errors on the same declarations more than once.
1634 if (CheckedDecls.count(Lambda)) {
1635 return;
1636 }
1637 CheckedDecls.insert(Lambda);
1638
1639 bool StrongRefToThisCaptured = false;
1640
1641 for (const LambdaCapture& Capture : Lambda->captures()) {
1642 // Check if any of the captures are ByRef. If they are, we have nothing to
1643 // report, as it's OK to capture raw pointers to refcounted objects so long as
1644 // the Lambda doesn't escape the current scope, which is required by ByRef
1645 // captures already.
1646 if (Capture.getCaptureKind() == LCK_ByRef) {
1647 return;
1648 }
1649
1650 // Check if this capture is byvalue, and captures a strong reference to this.
1651 // XXX: Do we want to make sure that this type which we are capturing is a "Smart Pointer" somehow?
1652 if (!StrongRefToThisCaptured &&
1653 Capture.capturesVariable() &&
1654 Capture.getCaptureKind() == LCK_ByCopy) {
1655 const VarDecl *Var = Capture.getCapturedVar();
1656 if (Var->hasInit()) {
1657 const Stmt *Init = Var->getInit();
1658
1659 // Ignore single argument constructors, and trivial nodes.
1660 while (true) {
1661 auto NewInit = IgnoreImplicit(Init);
1662 if (auto ConstructExpr = dyn_cast<CXXConstructExpr>(NewInit)) {
1663 if (ConstructExpr->getNumArgs() == 1) {
1664 NewInit = ConstructExpr->getArg(0);
1665 }
1666 }
1667 if (Init == NewInit) {
1668 break;
1669 }
1670 Init = NewInit;
1671 }
1672
1673 if (isa<CXXThisExpr>(Init)) {
1674 StrongRefToThisCaptured = true;
1675 }
1676 }
1677 }
1678 }
1679
1680 // Now we can go through and produce errors for any captured variables or this pointers.
1681 for (const LambdaCapture& Capture : Lambda->captures()) {
1682 if (Capture.capturesVariable()) {
1683 QualType Pointee = Capture.getCapturedVar()->getType()->getPointeeType();
1684
1685 if (!Pointee.isNull() && isClassRefCounted(Pointee)) {
1686 emitDiagnostics(Capture.getLocation(), Capture.getCapturedVar()->getName(), Pointee);
1687 return;
1688 }
1689 }
1690
1691 // The situation with captures of `this` is more complex. All captures of
1692 // `this` look the same-ish (they are LCK_This). We want to complain about
1693 // captures of `this` where `this` is a refcounted type, and the capture is
1694 // actually used in the body of the lambda (if the capture isn't used, then
1695 // we don't care, because it's only being captured in order to give access
1696 // to private methods).
1697 //
1698 // In addition, we don't complain about this, even if it is used, if it was
1699 // captured implicitly when the LambdaCaptureDefault was LCD_ByRef, as that
1700 // expresses the intent that the lambda won't leave the enclosing scope.
1701 bool ImplicitByRefDefaultedCapture =
1702 Capture.isImplicit() && Lambda->getLambdaCaptureDefault() == LCD_ByRef;
1703 if (Capture.capturesThis() &&
1704 !ImplicitByRefDefaultedCapture &&
1705 !StrongRefToThisCaptured) {
1706 ThisVisitor V(*this);
1707 bool NotAborted = V.TraverseDecl(const_cast<CXXMethodDecl *>(Lambda->getLambdaCallOperator()));
1708 if (!NotAborted) {
1709 return;
1710 }
1711 }
1712 }
1713 }
1714
1715 void DiagnosticsMatcher::RefCountedInsideLambdaChecker::emitDiagnostics(
1716 SourceLocation Loc, StringRef Name, QualType Type) {
1717 DiagnosticsEngine& Diag = Context->getDiagnostics();
1718 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
1719 DiagnosticIDs::Error, "Refcounted variable '%0' of type %1 cannot be captured by a lambda");
1720 unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
1721 DiagnosticIDs::Note, "Please consider using a smart pointer");
1722
1723 Diag.Report(Loc, ErrorID) << Name << Type;
1724 Diag.Report(Loc, NoteID);
1725 }
1726
1727 bool DiagnosticsMatcher::RefCountedInsideLambdaChecker::ThisVisitor::VisitCXXThisExpr(CXXThisExpr *This) {
1728 QualType Pointee = This->getType()->getPointeeType();
1729 if (!Pointee.isNull() && isClassRefCounted(Pointee)) {
1730 Checker.emitDiagnostics(This->getLocStart(), "this", Pointee);
1731 return false;
1732 }
1733
1734 return true;
1735 }
1736
1737 void DiagnosticsMatcher::ExplicitOperatorBoolChecker::run(
1738 const MatchFinder::MatchResult &Result) {
1739 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
1740 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
1741 DiagnosticIDs::Error, "bad implicit conversion operator for %0");
1742 unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
1743 DiagnosticIDs::Note, "consider adding the explicit keyword to %0");
1744 const CXXConversionDecl *Method =
1745 Result.Nodes.getNodeAs<CXXConversionDecl>("node");
1746 const CXXRecordDecl *Clazz = Method->getParent();
1747
1748 if (!Method->isExplicitSpecified() &&
1749 !MozChecker::hasCustomAnnotation(Method, "moz_implicit") &&
1750 !ASTIsInSystemHeader(Method->getASTContext(), *Method) &&
1751 isInterestingDeclForImplicitConversion(Method)) {
1752 Diag.Report(Method->getLocStart(), ErrorID) << Clazz;
1753 Diag.Report(Method->getLocStart(), NoteID) << "'operator bool'";
1754 }
1755 }
1756
1757 void DiagnosticsMatcher::NoDuplicateRefCntMemberChecker::run(
1758 const MatchFinder::MatchResult &Result) {
1759 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
1760 const CXXRecordDecl *D = Result.Nodes.getNodeAs<CXXRecordDecl>("decl");
1761 const FieldDecl *RefCntMember = getClassRefCntMember(D);
1762 const FieldDecl *FoundRefCntBase = nullptr;
1763
1764 if (!D->hasDefinition())
1765 return;
1766 D = D->getDefinition();
1767
1768 // If we don't have an mRefCnt member, and we have less than 2 superclasses,
1769 // we don't have to run this loop, as neither case will ever apply.
1770 if (!RefCntMember && D->getNumBases() < 2) {
1771 return;
1772 }
1773
1774 // Check every superclass for whether it has a base with a refcnt member, and
1775 // warn for those which do
1776 for (auto &Base : D->bases()) {
1777 // Determine if this base class has an mRefCnt member
1778 const FieldDecl *BaseRefCntMember = getBaseRefCntMember(Base.getType());
1779
1780 if (BaseRefCntMember) {
1781 if (RefCntMember) {
1782 // We have an mRefCnt, and superclass has an mRefCnt
1783 unsigned Error = Diag.getDiagnosticIDs()->getCustomDiagID(
1784 DiagnosticIDs::Error,
1785 "Refcounted record %0 has multiple mRefCnt members");
1786 unsigned Note1 = Diag.getDiagnosticIDs()->getCustomDiagID(
1787 DiagnosticIDs::Note, "Superclass %0 also has an mRefCnt member");
1788 unsigned Note2 = Diag.getDiagnosticIDs()->getCustomDiagID(
1789 DiagnosticIDs::Note,
1790 "Consider using the _INHERITED macros for AddRef and Release here");
1791
1792 Diag.Report(D->getLocStart(), Error) << D;
1793 Diag.Report(BaseRefCntMember->getLocStart(), Note1)
1794 << BaseRefCntMember->getParent();
1795 Diag.Report(RefCntMember->getLocStart(), Note2);
1796 }
1797
1798 if (FoundRefCntBase) {
1799 unsigned Error = Diag.getDiagnosticIDs()->getCustomDiagID(
1800 DiagnosticIDs::Error,
1801 "Refcounted record %0 has multiple superclasses with mRefCnt members");
1802 unsigned Note = Diag.getDiagnosticIDs()->getCustomDiagID(
1803 DiagnosticIDs::Note,
1804 "Superclass %0 has an mRefCnt member");
1805
1806 // superclass has mRefCnt, and another superclass also has an mRefCnt
1807 Diag.Report(D->getLocStart(), Error) << D;
1808 Diag.Report(BaseRefCntMember->getLocStart(), Note)
1809 << BaseRefCntMember->getParent();
1810 Diag.Report(FoundRefCntBase->getLocStart(), Note)
1811 << FoundRefCntBase->getParent();
1812 }
1813
1814 // Record that we've found a base with a mRefCnt member
1815 FoundRefCntBase = BaseRefCntMember;
1816 }
1817 }
1818 }
1819
1820 void DiagnosticsMatcher::NeedsNoVTableTypeChecker::run(
1821 const MatchFinder::MatchResult &Result) {
1822 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
1823 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
1824 DiagnosticIDs::Error,
1825 "%0 cannot be instantiated because %1 has a VTable");
1826 unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
1827 DiagnosticIDs::Note, "bad instantiation of %0 requested here");
1828
1829 const ClassTemplateSpecializationDecl *Specialization =
1830 Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("node");
1831
1832 // Get the offending template argument
1833 QualType Offender;
1834 const TemplateArgumentList &Args =
1835 Specialization->getTemplateInstantiationArgs();
1836 for (unsigned i = 0; i < Args.size(); ++i) {
1837 Offender = Args[i].getAsType();
1838 if (typeHasVTable(Offender)) {
1839 break;
1840 }
1841 }
1842
1843 Diag.Report(Specialization->getLocStart(), ErrorID) << Specialization
1844 << Offender;
1845 Diag.Report(Specialization->getPointOfInstantiation(), NoteID)
1846 << Specialization;
1847 }
1848
1849 void DiagnosticsMatcher::NonMemMovableTemplateArgChecker::run(
1850 const MatchFinder::MatchResult &Result) {
1851 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
1852 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
1853 DiagnosticIDs::Error,
1854 "Cannot instantiate %0 with non-memmovable template argument %1");
1855 unsigned Note1ID = Diag.getDiagnosticIDs()->getCustomDiagID(
1856 DiagnosticIDs::Note, "instantiation of %0 requested here");
1857
1858 // Get the specialization
1859 const ClassTemplateSpecializationDecl *Specialization =
1860 Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("specialization");
1861 SourceLocation RequestLoc = Specialization->getPointOfInstantiation();
1862
1863 // Report an error for every template argument which is non-memmovable
1864 const TemplateArgumentList &Args =
1865 Specialization->getTemplateInstantiationArgs();
1866 for (unsigned i = 0; i < Args.size(); ++i) {
1867 QualType ArgType = Args[i].getAsType();
1868 if (NonMemMovable.hasEffectiveAnnotation(ArgType)) {
1869 Diag.Report(Specialization->getLocation(), ErrorID) << Specialization
1870 << ArgType;
1871 // XXX It would be really nice if we could get the instantiation stack
1872 // information
1873 // from Sema such that we could print a full template instantiation stack,
1874 // however,
1875 // it seems as though that information is thrown out by the time we get
1876 // here so we
1877 // can only report one level of template specialization (which in many
1878 // cases won't
1879 // be useful)
1880 Diag.Report(RequestLoc, Note1ID) << Specialization;
1881 NonMemMovable.dumpAnnotationReason(Diag, ArgType, RequestLoc);
1882 }
1883 }
1884 }
1885
1886 void DiagnosticsMatcher::NonMemMovableMemberChecker::run(
1887 const MatchFinder::MatchResult &Result) {
1888 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
1889 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
1890 DiagnosticIDs::Error,
1891 "class %0 cannot have non-memmovable member %1 of type %2");
1892
1893 // Get the specialization
1894 const CXXRecordDecl* Declaration =
1895 Result.Nodes.getNodeAs<CXXRecordDecl>("decl");
1896
1897 // Report an error for every member which is non-memmovable
1898 for (const FieldDecl *Field : Declaration->fields()) {
1899 QualType Type = Field->getType();
1900 if (NonMemMovable.hasEffectiveAnnotation(Type)) {
1901 Diag.Report(Field->getLocation(), ErrorID) << Declaration
1902 << Field
1903 << Type;
1904 NonMemMovable.dumpAnnotationReason(Diag, Type, Declaration->getLocation());
1905 }
1906 }
1907 }
1908
1909 void DiagnosticsMatcher::ExplicitImplicitChecker::run(
1910 const MatchFinder::MatchResult &Result) {
1911 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
1912 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
1913 DiagnosticIDs::Error, "bad implicit conversion constructor for %0");
1914 unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
1915 DiagnosticIDs::Note,
1916 "consider adding the explicit keyword to the constructor");
1917
1918 // We've already checked everything in the matcher, so we just have to report
1919 // the error.
1920
1921 const CXXConstructorDecl *Ctor =
1922 Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");
1923 const CXXRecordDecl *Declaration =
1924 Result.Nodes.getNodeAs<CXXRecordDecl>("class");
1925
1926 Diag.Report(Ctor->getLocation(), ErrorID) << Declaration->getDeclName();
1927 Diag.Report(Ctor->getLocation(), NoteID);
1928 }
1929
1930 void DiagnosticsMatcher::NoAutoTypeChecker::run(
1931 const MatchFinder::MatchResult &Result) {
1932 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
1933 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
1934 DiagnosticIDs::Error, "Cannot use auto to declare a variable of type %0");
1935 unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
1936 DiagnosticIDs::Note, "Please write out this type explicitly");
1937
1938 const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>("node");
1939
1940 Diag.Report(D->getLocation(), ErrorID) << D->getType();
1941 Diag.Report(D->getLocation(), NoteID);
1942 }
1943
1944 void DiagnosticsMatcher::NoExplicitMoveConstructorChecker::run(
1945 const MatchFinder::MatchResult &Result) {
1946 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
1947 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
1948 DiagnosticIDs::Error, "Move constructors may not be marked explicit");
1949
1950 // Everything we needed to know was checked in the matcher - we just report
1951 // the error here
1952 const CXXConstructorDecl *D =
1953 Result.Nodes.getNodeAs<CXXConstructorDecl>("node");
1954
1955 Diag.Report(D->getLocation(), ErrorID);
1956 }
1957
1958 void DiagnosticsMatcher::RefCountedCopyConstructorChecker::run(
1959 const MatchFinder::MatchResult &Result) {
1960 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
1961 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
1962 DiagnosticIDs::Error, "Invalid use of compiler-provided copy constructor "
1963 "on refcounted type");
1964 unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
1965 DiagnosticIDs::Note,
1966 "The default copy constructor also copies the "
1967 "default mRefCnt property, leading to reference "
1968 "count imbalance issues. Please provide your own "
1969 "copy constructor which only copies the fields which "
1970 "need to be copied");
1971
1972 // Everything we needed to know was checked in the matcher - we just report
1973 // the error here
1974 const CXXConstructExpr *E = Result.Nodes.getNodeAs<CXXConstructExpr>("node");
1975
1976 Diag.Report(E->getLocation(), ErrorID);
1977 Diag.Report(E->getLocation(), NoteID);
1978 }
1979
1980 void DiagnosticsMatcher::AssertAssignmentChecker::run(
1981 const MatchFinder::MatchResult &Result) {
1982 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
1983 unsigned AssignInsteadOfComp = Diag.getDiagnosticIDs()->getCustomDiagID(
1984 DiagnosticIDs::Error, "Forbidden assignment in assert expression");
1985 const CallExpr *FuncCall = Result.Nodes.getNodeAs<CallExpr>("funcCall");
1986
1987 if (FuncCall && hasSideEffectAssignment(FuncCall)) {
1988 Diag.Report(FuncCall->getLocStart(), AssignInsteadOfComp);
1989 }
1990 }
1991
1992 void DiagnosticsMatcher::KungFuDeathGripChecker::run(
1993 const MatchFinder::MatchResult &Result) {
1994 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
1995 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
1996 DiagnosticIDs::Error,
1997 "Unused \"kungFuDeathGrip\" %0 objects constructed from %1 are prohibited");
1998
1999 unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
2000 DiagnosticIDs::Note,
2001 "Please switch all accesses to this %0 to go through '%1', or explicitly pass '%1' to `mozilla::Unused`");
2002
2003 const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>("decl");
2004 if (D->isReferenced() || !D->hasLocalStorage() || !D->hasInit()) {
2005 return;
2006 }
2007
2008 // Not interested in parameters.
2009 if (isa<ImplicitParamDecl>(D) || isa<ParmVarDecl>(D)) {
2010 return;
2011 }
2012
2013 const Expr *E = IgnoreImplicit(D->getInit());
2014 const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(E);
2015 if (CE && CE->getNumArgs() == 0) {
2016 // We don't report an error when we construct and don't use a nsCOMPtr /
2017 // nsRefPtr with no arguments. We don't report it because the error is not
2018 // related to the current check. In the future it may be reported through a
2019 // more generic mechanism.
2020 return;
2021 }
2022
2023 // We don't want to look at the single argument conversion constructors
2024 // which are inbetween the declaration and the actual object which we are
2025 // assigning into the nsCOMPtr/RefPtr. To do this, we repeatedly
2026 // IgnoreImplicit, then look at the expression. If it is one of these
2027 // conversion constructors, we ignore it and continue to dig.
2028 while ((CE = dyn_cast<CXXConstructExpr>(E)) && CE->getNumArgs() == 1) {
2029 E = IgnoreImplicit(CE->getArg(0));
2030 }
2031
2032 // We allow taking a kungFuDeathGrip of `this` because it cannot change
2033 // beneath us, so calling directly through `this` is OK. This is the same
2034 // for local variable declarations.
2035 //
2036 // We also don't complain about unused RefPtrs which are constructed from
2037 // the return value of a new expression, as these are required in order to
2038 // immediately destroy the value created (which was presumably created for
2039 // its side effects), and are not used as a death grip.
2040 if (isa<CXXThisExpr>(E) || isa<DeclRefExpr>(E) || isa<CXXNewExpr>(E)) {
2041 return;
2042 }
2043
2044 // These types are assigned into nsCOMPtr and RefPtr for their side effects,
2045 // and not as a kungFuDeathGrip. We don't want to consider RefPtr and nsCOMPtr
2046 // types which are initialized with these types as errors.
2047 const TagDecl *TD = E->getType()->getAsTagDecl();
2048 if (TD && TD->getIdentifier()) {
2049 static const char *IgnoreTypes[] = {
2050 "already_AddRefed",
2051 "nsGetServiceByCID",
2052 "nsGetServiceByCIDWithError",
2053 "nsGetServiceByContractID",
2054 "nsGetServiceByContractIDWithError",
2055 "nsCreateInstanceByCID",
2056 "nsCreateInstanceByContractID",
2057 "nsCreateInstanceFromFactory",
2058 };
2059
2060 for (uint32_t i = 0; i < sizeof(IgnoreTypes) / sizeof(IgnoreTypes[0]); ++i) {
2061 if (TD->getName() == IgnoreTypes[i]) {
2062 return;
2063 }
2064 }
2065 }
2066
2067 // Report the error
2068 const char *ErrThing;
2069 const char *NoteThing;
2070 if (isa<MemberExpr>(E)) {
2071 ErrThing = "members";
2072 NoteThing = "member";
2073 } else {
2074 ErrThing = "temporary values";
2075 NoteThing = "value";
2076 }
2077
2078 // We cannot provide the note if we don't have an initializer
2079 Diag.Report(D->getLocStart(), ErrorID) << D->getType() << ErrThing;
2080 Diag.Report(E->getLocStart(), NoteID) << NoteThing << getNameChecked(D);
2081 }
2082
2083 void DiagnosticsMatcher::SprintfLiteralChecker::run(
2084 const MatchFinder::MatchResult &Result) {
2085 if (!Result.Context->getLangOpts().CPlusPlus) {
2086 // SprintfLiteral is not usable in C, so there is no point in issuing these
2087 // warnings.
2088 return;
2089 }
2090
2091 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
2092 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
2093 DiagnosticIDs::Error, "Use %1 instead of %0 when writing into a character array.");
2094 unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
2095 DiagnosticIDs::Note, "This will prevent passing in the wrong size to %0 accidentally.");
2096
2097 const CallExpr *D = Result.Nodes.getNodeAs<CallExpr>("funcCall");
2098
2099 StringRef Name = D->getDirectCallee()->getName();
2100 const char *Replacement;
2101 if (Name == "snprintf") {
2102 Replacement = "SprintfLiteral";
2103 } else {
2104 assert(Name == "vsnprintf");
2105 Replacement = "VsprintfLiteral";
2106 }
2107
2108 const DeclRefExpr *Buffer = Result.Nodes.getNodeAs<DeclRefExpr>("buffer");
2109 const DeclRefExpr *Size = Result.Nodes.getNodeAs<DeclRefExpr>("size");
2110 if (Size) {
2111 // Match calls like snprintf(x, sizeof(x), ...).
2112 if (Buffer->getFoundDecl() != Size->getFoundDecl()) {
2113 return;
2114 }
2115
2116 Diag.Report(D->getLocStart(), ErrorID) << Name << Replacement;
2117 Diag.Report(D->getLocStart(), NoteID) << Name;
2118 return;
2119 }
2120
2121 const QualType QType = Buffer->getType();
2122 const ConstantArrayType *Type = dyn_cast<ConstantArrayType>(QType.getTypePtrOrNull());
2123 if (Type) {
2124 // Match calls like snprintf(x, 100, ...), where x is int[100];
2125 const IntegerLiteral *Literal = Result.Nodes.getNodeAs<IntegerLiteral>("immediate");
2126 if (!Literal) {
2127 // Match calls like: const int y = 100; snprintf(x, y, ...);
2128 Literal = Result.Nodes.getNodeAs<IntegerLiteral>("constant");
2129 }
2130
2131 if (Type->getSize().ule(Literal->getValue())) {
2132 Diag.Report(D->getLocStart(), ErrorID) << Name << Replacement;
2133 Diag.Report(D->getLocStart(), NoteID) << Name;
2134 }
2135 }
2136 }
2137
2138 bool DiagnosticsMatcher::OverrideBaseCallChecker::isRequiredBaseMethod(
2139 const CXXMethodDecl *Method) {
2140 return MozChecker::hasCustomAnnotation(Method, "moz_required_base_method");
2141 }
2142
2143 void DiagnosticsMatcher::OverrideBaseCallChecker::evaluateExpression(
2144 const Stmt *StmtExpr, std::list<const CXXMethodDecl*> &MethodList) {
2145 // Continue while we have methods in our list
2146 if (!MethodList.size()) {
2147 return;
2148 }
2149
2150 if (auto MemberFuncCall = dyn_cast<CXXMemberCallExpr>(StmtExpr)) {
2151 if (auto Method = dyn_cast<CXXMethodDecl>(
2152 MemberFuncCall->getDirectCallee())) {
2153 findBaseMethodCall(Method, MethodList);
2154 }
2155 }
2156
2157 for (auto S : StmtExpr->children()) {
2158 if (S) {
2159 evaluateExpression(S, MethodList);
2160 }
2161 }
2162 }
2163
2164 void DiagnosticsMatcher::OverrideBaseCallChecker::getRequiredBaseMethod(
2165 const CXXMethodDecl *Method,
2166 std::list<const CXXMethodDecl*>& MethodsList) {
2167
2168 if (isRequiredBaseMethod(Method)) {
2169 MethodsList.push_back(Method);
2170 } else {
2171 // Loop through all it's base methods.
2172 for (auto BaseMethod = Method->begin_overridden_methods();
2173 BaseMethod != Method->end_overridden_methods(); BaseMethod++) {
2174 getRequiredBaseMethod(*BaseMethod, MethodsList);
2175 }
2176 }
2177 }
2178
2179 void DiagnosticsMatcher::OverrideBaseCallChecker::findBaseMethodCall(
2180 const CXXMethodDecl* Method,
2181 std::list<const CXXMethodDecl*>& MethodsList) {
2182
2183 MethodsList.remove(Method);
2184 // Loop also through all it's base methods;
2185 for (auto BaseMethod = Method->begin_overridden_methods();
2186 BaseMethod != Method->end_overridden_methods(); BaseMethod++) {
2187 findBaseMethodCall(*BaseMethod, MethodsList);
2188 }
2189 }
2190
2191 void DiagnosticsMatcher::OverrideBaseCallChecker::run(
2192 const MatchFinder::MatchResult &Result) {
2193 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
2194 unsigned OverrideBaseCallCheckID = Diag.getDiagnosticIDs()->getCustomDiagID(
2195 DiagnosticIDs::Error,
2196 "Method %0 must be called in all overrides, but is not called in "
2197 "this override defined for class %1");
2198 const CXXRecordDecl *Decl = Result.Nodes.getNodeAs<CXXRecordDecl>("class");
2199
2200 // Loop through the methods and look for the ones that are overridden.
2201 for (auto Method : Decl->methods()) {
2202 // If this method doesn't override other methods or it doesn't have a body,
2203 // continue to the next declaration.
2204 if (!Method->size_overridden_methods() || !Method->hasBody()) {
2205 continue;
2206 }
2207
2208 // Preferred the usage of list instead of vector in order to avoid
2209 // calling erase-remove when deleting items
2210 std::list<const CXXMethodDecl*> MethodsList;
2211 // For each overridden method push it to a list if it meets our
2212 // criteria
2213 for (auto BaseMethod = Method->begin_overridden_methods();
2214 BaseMethod != Method->end_overridden_methods(); BaseMethod++) {
2215 getRequiredBaseMethod(*BaseMethod, MethodsList);
2216 }
2217
2218 // If no method has been found then no annotation was used
2219 // so checking is not needed
2220 if (!MethodsList.size()) {
2221 continue;
2222 }
2223
2224 // Loop through the body of our method and search for calls to
2225 // base methods
2226 evaluateExpression(Method->getBody(), MethodsList);
2227
2228 // If list is not empty pop up errors
2229 for (auto BaseMethod : MethodsList) {
2230 Diag.Report(Method->getLocation(), OverrideBaseCallCheckID)
2231 << BaseMethod->getQualifiedNameAsString()
2232 << Decl->getName();
2233 }
2234 }
2235 }
2236
2237 void DiagnosticsMatcher::OverrideBaseCallUsageChecker::run(
2238 const MatchFinder::MatchResult &Result) {
2239 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
2240 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
2241 DiagnosticIDs::Error,
2242 "MOZ_REQUIRED_BASE_METHOD can be used only on virtual methods");
2243 const CXXMethodDecl *Method = Result.Nodes.getNodeAs<CXXMethodDecl>("method");
2244
2245 Diag.Report(Method->getLocation(), ErrorID);
2246 }
2247
2248 void DiagnosticsMatcher::NonParamInsideFunctionDeclChecker::run(
2249 const MatchFinder::MatchResult &Result) {
2250 static DenseSet<const FunctionDecl*> CheckedFunctionDecls;
2251
2252 const FunctionDecl *func = Result.Nodes.getNodeAs<FunctionDecl>("func");
2253 if (!func) {
2254 const LambdaExpr *lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
2255 if (lambda) {
2256 func = lambda->getCallOperator();
2257 }
2258 }
2259
2260 if (!func) {
2261 return;
2262 }
2263
2264 if (func->isDeleted()) {
2265 return;
2266 }
2267
2268 // Don't report errors on the same declarations more than once.
2269 if (CheckedFunctionDecls.count(func)) {
2270 return;
2271 }
2272 CheckedFunctionDecls.insert(func);
2273
2274 const ClassTemplateSpecializationDecl *Spec =
2275 Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("spec");
2276
2277 DiagnosticsEngine &Diag = Result.Context->getDiagnostics();
2278 unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID(
2279 DiagnosticIDs::Error, "Type %0 must not be used as parameter");
2280 unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
2281 DiagnosticIDs::Note, "Please consider passing a const reference instead");
2282 unsigned SpecNoteID = Diag.getDiagnosticIDs()->getCustomDiagID(
2283 DiagnosticIDs::Note, "The bad argument was passed to %0 here");
2284
2285 for (ParmVarDecl *p : func->parameters()) {
2286 QualType T = p->getType().withoutLocalFastQualifiers();
2287 if (NonParam.hasEffectiveAnnotation(T)) {
2288 Diag.Report(p->getLocation(), ErrorID) << T;
2289 Diag.Report(p->getLocation(), NoteID);
2290
2291 if (Spec) {
2292 Diag.Report(Spec->getPointOfInstantiation(), SpecNoteID)
2293 << Spec->getSpecializedTemplate();
2294 }
2295 }
2296 }
2297 }
2298
2299 class MozCheckAction : public PluginASTAction {
2300 public:
2301 ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI,
2302 StringRef FileName) override {
2303 #if CLANG_VERSION_FULL >= 306
2304 std::unique_ptr<MozChecker> Checker(llvm::make_unique<MozChecker>(CI));
2305 ASTConsumerPtr Other(Checker->getOtherConsumer());
2306
2307 std::vector<ASTConsumerPtr> Consumers;
2308 Consumers.push_back(std::move(Checker));
2309 Consumers.push_back(std::move(Other));
2310 return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
2311 #else
2312 MozChecker *Checker = new MozChecker(CI);
2313
2314 ASTConsumer *Consumers[] = {Checker, Checker->getOtherConsumer()};
2315 return new MultiplexConsumer(Consumers);
2316 #endif
2317 }
2318
2319 bool ParseArgs(const CompilerInstance &CI,
2320 const std::vector<std::string> &Args) override {
2321 return true;
2322 }
2323 };
2324 }
2325
2326 static FrontendPluginRegistry::Add<MozCheckAction> X("moz-check",
2327 "check moz action");
2328 // Export the registry on Windows.
2329 #ifdef LLVM_EXPORT_REGISTRY
2330 LLVM_EXPORT_REGISTRY(FrontendPluginRegistry)
2331 #endif
2332