author | Ehsan Akhgari <ehsan@mozilla.com> |
Sat, 17 Dec 2016 21:14:37 -0500 | |
changeset 327508 | 8222951c9369ca13c6358bc32c9d5da6c6c2289b |
parent 327507 | ddfb48730883391cb38347d34917deaa978b9bc1 |
child 327509 | 409bdaed6b9f41f001db03eb5a5469e5ad5685e5 |
push id | 31135 |
push user | kwierso@gmail.com |
push date | Thu, 29 Dec 2016 20:04:00 +0000 |
treeherder | mozilla-central@79ef93672445 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | mystor |
bugs | 1324315 |
milestone | 53.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/build/clang-plugin/ArithmeticArgChecker.cpp +++ b/build/clang-plugin/ArithmeticArgChecker.cpp @@ -1,17 +1,17 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ArithmeticArgChecker.h" #include "CustomMatchers.h" -void ArithmeticArgChecker::registerMatcher(MatchFinder& AstMatcher) { - AstMatcher.addMatcher( +void ArithmeticArgChecker::registerMatchers(MatchFinder* AstMatcher) { + AstMatcher->addMatcher( callExpr(allOf(hasDeclaration(noArithmeticExprInArgs()), anyOf(hasDescendant( binaryOperator( allOf(binaryArithmeticOperator(), hasLHS(hasDescendant(declRefExpr())), hasRHS(hasDescendant(declRefExpr())))) .bind("node")), hasDescendant( @@ -19,17 +19,17 @@ void ArithmeticArgChecker::registerMatch allOf(unaryArithmeticOperator(), hasUnaryOperand(allOf( hasType(builtinType()), anyOf(hasDescendant(declRefExpr()), declRefExpr()))))) .bind("node"))))) .bind("call"), this); - AstMatcher.addMatcher( + AstMatcher->addMatcher( cxxConstructExpr( allOf(hasDeclaration(noArithmeticExprInArgs()), anyOf(hasDescendant( binaryOperator( allOf(binaryArithmeticOperator(), hasLHS(hasDescendant(declRefExpr())), hasRHS(hasDescendant(declRefExpr())))) .bind("node")), @@ -40,22 +40,19 @@ void ArithmeticArgChecker::registerMatch hasType(builtinType()), anyOf(hasDescendant(declRefExpr()), declRefExpr()))))) .bind("node"))))) .bind("call"), this); } -void ArithmeticArgChecker::run( +void ArithmeticArgChecker::check( const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, - "cannot pass an arithmetic expression of built-in types to %0"); + const char* Error = "cannot pass an arithmetic expression of built-in types to %0"; const Expr *Expression = Result.Nodes.getNodeAs<Expr>("node"); if (const CallExpr *Call = Result.Nodes.getNodeAs<CallExpr>("call")) { - Diag.Report(Expression->getLocStart(), ErrorID) << Call->getDirectCallee(); + diag(Expression->getLocStart(), Error, DiagnosticIDs::Error) << Call->getDirectCallee(); } else if (const CXXConstructExpr *Ctr = Result.Nodes.getNodeAs<CXXConstructExpr>("call")) { - Diag.Report(Expression->getLocStart(), ErrorID) << Ctr->getConstructor(); + diag(Expression->getLocStart(), Error, DiagnosticIDs::Error) << Ctr->getConstructor(); } }
--- a/build/clang-plugin/ArithmeticArgChecker.h +++ b/build/clang-plugin/ArithmeticArgChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef ArithmeticArgChecker_h__ #define ArithmeticArgChecker_h__ #include "plugin.h" -class ArithmeticArgChecker : public MatchFinder::MatchCallback { +class ArithmeticArgChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + ArithmeticArgChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
--- a/build/clang-plugin/AssertAssignmentChecker.cpp +++ b/build/clang-plugin/AssertAssignmentChecker.cpp @@ -1,24 +1,23 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "AssertAssignmentChecker.h" #include "CustomMatchers.h" -void AssertAssignmentChecker::registerMatcher(MatchFinder& AstMatcher) { - AstMatcher.addMatcher( +void AssertAssignmentChecker::registerMatchers(MatchFinder* AstMatcher) { + AstMatcher->addMatcher( callExpr(isAssertAssignmentTestFunc()).bind("funcCall"), this); } -void AssertAssignmentChecker::run( +void AssertAssignmentChecker::check( const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned AssignInsteadOfComp = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "Forbidden assignment in assert expression"); const CallExpr *FuncCall = Result.Nodes.getNodeAs<CallExpr>("funcCall"); if (FuncCall && hasSideEffectAssignment(FuncCall)) { - Diag.Report(FuncCall->getLocStart(), AssignInsteadOfComp); + diag(FuncCall->getLocStart(), + "Forbidden assignment in assert expression", + DiagnosticIDs::Error); } }
--- a/build/clang-plugin/AssertAssignmentChecker.h +++ b/build/clang-plugin/AssertAssignmentChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef AssertAssignmentChecker_h__ #define AssertAssignmentChecker_h__ #include "plugin.h" -class AssertAssignmentChecker : public MatchFinder::MatchCallback { +class AssertAssignmentChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + AssertAssignmentChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
new file mode 100644 --- /dev/null +++ b/build/clang-plugin/BaseCheck.h @@ -0,0 +1,34 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef BaseCheck_h__ +#define BaseCheck_h__ + +class MozContext {}; +typedef MozContext ContextType; + +class BaseCheck : public MatchFinder::MatchCallback { +public: + BaseCheck(StringRef CheckName, ContextType* Context) {} + virtual void registerMatchers(MatchFinder *Finder) {} + virtual void check(const MatchFinder::MatchResult &Result) {} + DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, + DiagnosticIDs::Level Level = DiagnosticIDs::Warning) { + DiagnosticsEngine &Diag = Context->getDiagnostics(); + unsigned ID = Diag.getDiagnosticIDs()->getCustomDiagID(Level, Description); + // We treat all diagnostics as errors here. + return Diag.Report(Loc, ID); + } + +private: + void run(const MatchFinder::MatchResult &Result) override { + Context = Result.Context; + check(Result); + } + +private: + ASTContext* Context; +}; + +#endif
new file mode 100644 --- /dev/null +++ b/build/clang-plugin/Checks.inc @@ -0,0 +1,27 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// The list of checker classes that are compatible with clang-tidy. + +CHECK(ArithmeticArgChecker, "arithmetic-argument") +CHECK(AssertAssignmentChecker, "assignment-in-assert") +CHECK(ExplicitImplicitChecker, "implicit-constructor") +CHECK(ExplicitOperatorBoolChecker, "explicit-operator-bool") +CHECK(KungFuDeathGripChecker, "kungfu-death-grip") +CHECK(NaNExprChecker, "nan-expr") +CHECK(NeedsNoVTableTypeChecker, "needs-no-vtable-type") +CHECK(NoAddRefReleaseOnReturnChecker, "no-addref-release-on-return") +CHECK(NoAutoTypeChecker, "no-auto-type") +CHECK(NoDuplicateRefCntMemberChecker, "no-duplicate-refcnt-member") +CHECK(NoExplicitMoveConstructorChecker, "no-explicit-move-constructor") +CHECK(NonMemMovableMemberChecker, "non-memmovable-member") +CHECK(NonMemMovableTemplateArgChecker, "non-memmovable-template-arg") +CHECK(NonParamInsideFunctionDeclChecker, "non-memmovable-template-arg") +CHECK(OverrideBaseCallChecker, "override-base-call") +CHECK(OverrideBaseCallUsageChecker, "override-base-call-usage") +CHECK(RefCountedCopyConstructorChecker, "refcounted-copy-constructor") +CHECK(RefCountedInsideLambdaChecker, "refcounted-inside-lambda") +CHECK(ScopeChecker, "scope") +CHECK(SprintfLiteralChecker, "sprintf-literal") +CHECK(TrivialCtorDtorChecker, "trivial-constructor-destructor")
new file mode 100644 --- /dev/null +++ b/build/clang-plugin/ChecksIncludes.inc @@ -0,0 +1,29 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// The list of #include directives necessary for the checker classes that +// are compatible with clang-tidy. + +#include "ArithmeticArgChecker.h" +#include "AssertAssignmentChecker.h" +#include "ExplicitImplicitChecker.h" +#include "ExplicitOperatorBoolChecker.h" +#include "KungFuDeathGripChecker.h" +#include "NaNExprChecker.h" +#include "NeedsNoVTableTypeChecker.h" +#include "NoAddRefReleaseOnReturnChecker.h" +#include "NoAutoTypeChecker.h" +#include "NoDuplicateRefCntMemberChecker.h" +#include "NoExplicitMoveConstructorChecker.h" +#include "NonMemMovableMemberChecker.h" +#include "NonMemMovableTemplateArgChecker.h" +#include "NonParamInsideFunctionDeclChecker.h" +#include "OverrideBaseCallChecker.h" +#include "OverrideBaseCallUsageChecker.h" +#include "RefCountedCopyConstructorChecker.h" +#include "RefCountedInsideLambdaChecker.h" +#include "ScopeChecker.h" +#include "SprintfLiteralChecker.h" +#include "TrivialCtorDtorChecker.h" +
--- a/build/clang-plugin/CustomTypeAnnotation.cpp +++ b/build/clang-plugin/CustomTypeAnnotation.cpp @@ -66,16 +66,64 @@ void CustomTypeAnnotation::dumpAnnotatio return; } T = Reason.Type; Reason = directAnnotationReason(T); } } +void CustomTypeAnnotation::dumpAnnotationReason(BaseCheck &Check, + QualType T, + SourceLocation Loc) { + const char* Inherits = + "%1 is a %0 type because it inherits from a %0 type %2"; + const char* Member = + "%1 is a %0 type because member %2 is a %0 type %3"; + const char* Array = + "%1 is a %0 type because it is an array of %0 type %2"; + const char* Templ = + "%1 is a %0 type because it has a template argument %0 type %2"; + + AnnotationReason Reason = directAnnotationReason(T); + for (;;) { + switch (Reason.Kind) { + case RK_ArrayElement: + Check.diag(Loc, Array, DiagnosticIDs::Note) << Pretty << T << Reason.Type; + break; + case RK_BaseClass: { + const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl(); + assert(Declaration && "This type should be a C++ class"); + + Check.diag(Declaration->getLocation(), Inherits, DiagnosticIDs::Note) + << Pretty << T << Reason.Type; + break; + } + case RK_Field: + Check.diag(Reason.Field->getLocation(), Member, DiagnosticIDs::Note) + << Pretty << T << Reason.Field << Reason.Type; + break; + case RK_TemplateInherited: { + const CXXRecordDecl *Declaration = T->getAsCXXRecordDecl(); + assert(Declaration && "This type should be a C++ class"); + + Check.diag(Declaration->getLocation(), Templ, DiagnosticIDs::Note) + << Pretty << T << Reason.Type; + break; + } + default: + // FIXME (bug 1203263): note the original annotation. + return; + } + + T = Reason.Type; + Reason = directAnnotationReason(T); + } +} + bool CustomTypeAnnotation::hasLiteralAnnotation(QualType T) const { #if CLANG_VERSION_FULL >= 306 if (const TagDecl *D = T->getAsTagDecl()) { #else if (const CXXRecordDecl *D = T->getAsCXXRecordDecl()) { #endif return hasFakeAnnotation(D) || MozChecker::hasCustomAnnotation(D, Spelling); }
--- a/build/clang-plugin/CustomTypeAnnotation.h +++ b/build/clang-plugin/CustomTypeAnnotation.h @@ -36,24 +36,26 @@ public: virtual ~CustomTypeAnnotation() {} // Checks if this custom annotation "effectively affects" the given type. bool hasEffectiveAnnotation(QualType T) { return directAnnotationReason(T).valid(); } void dumpAnnotationReason(DiagnosticsEngine &Diag, QualType T, SourceLocation Loc); + void dumpAnnotationReason(BaseCheck &Check, QualType T, + SourceLocation Loc); - void reportErrorIfPresent(DiagnosticsEngine &Diag, QualType T, - SourceLocation Loc, unsigned ErrorID, - unsigned NoteID) { + void reportErrorIfPresent(BaseCheck &Check, QualType T, + SourceLocation Loc, const char* Error, + const char* Note) { if (hasEffectiveAnnotation(T)) { - Diag.Report(Loc, ErrorID) << T; - Diag.Report(Loc, NoteID); - dumpAnnotationReason(Diag, T, Loc); + Check.diag(Loc, Error, DiagnosticIDs::Error) << T; + Check.diag(Loc, Note, DiagnosticIDs::Note); + dumpAnnotationReason(Check, T, Loc); } } private: bool hasLiteralAnnotation(QualType T) const; AnnotationReason directAnnotationReason(QualType T); AnnotationReason tmplArgAnnotationReason(ArrayRef<TemplateArgument> Args);
--- a/build/clang-plugin/DiagnosticsMatcher.cpp +++ b/build/clang-plugin/DiagnosticsMatcher.cpp @@ -1,29 +1,16 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "DiagnosticsMatcher.h" -DiagnosticsMatcher::DiagnosticsMatcher() { - Scope.registerMatcher(AstMatcher); - ArithmeticArg.registerMatcher(AstMatcher); - TrivialCtorDtor.registerMatcher(AstMatcher); - NaNExpr.registerMatcher(AstMatcher); - NoAddRefReleaseOnReturn.registerMatcher(AstMatcher); - RefCountedInsideLambda.registerMatcher(AstMatcher); - ExplicitOperatorBool.registerMatcher(AstMatcher); - NoDuplicateRefCntMember.registerMatcher(AstMatcher); - NeedsNoVTableType.registerMatcher(AstMatcher); - NonMemMovableTemplateArg.registerMatcher(AstMatcher); - NonMemMovableMember.registerMatcher(AstMatcher); - ExplicitImplicit.registerMatcher(AstMatcher); - NoAutoType.registerMatcher(AstMatcher); - NoExplicitMoveConstructor.registerMatcher(AstMatcher); - RefCountedCopyConstructor.registerMatcher(AstMatcher); - AssertAssignment.registerMatcher(AstMatcher); - KungFuDeathGrip.registerMatcher(AstMatcher); - SprintfLiteral.registerMatcher(AstMatcher); - OverrideBaseCall.registerMatcher(AstMatcher); - OverrideBaseCallUsage.registerMatcher(AstMatcher); - NonParamInsideFunctionDecl.registerMatcher(AstMatcher); +DiagnosticsMatcher::DiagnosticsMatcher() : +#define CHECK(cls, name) cls ## _(name), +#include "Checks.inc" +#undef CHECK + AstMatcher() +{ +#define CHECK(cls, name) cls ## _.registerMatchers(&AstMatcher); +#include "Checks.inc" +#undef CHECK }
--- a/build/clang-plugin/DiagnosticsMatcher.h +++ b/build/clang-plugin/DiagnosticsMatcher.h @@ -1,61 +1,23 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef DiagnosticsMatcher_h__ #define DiagnosticsMatcher_h__ -#include "ArithmeticArgChecker.h" -#include "AssertAssignmentChecker.h" -#include "ExplicitImplicitChecker.h" -#include "ExplicitOperatorBoolChecker.h" -#include "KungFuDeathGripChecker.h" -#include "NaNExprChecker.h" -#include "NeedsNoVTableTypeChecker.h" -#include "NoAddRefReleaseOnReturnChecker.h" -#include "NoAutoTypeChecker.h" -#include "NoDuplicateRefCntMemberChecker.h" -#include "NoExplicitMoveConstructorChecker.h" -#include "NonMemMovableMemberChecker.h" -#include "NonMemMovableTemplateArgChecker.h" -#include "NonParamInsideFunctionDeclChecker.h" -#include "OverrideBaseCallChecker.h" -#include "OverrideBaseCallUsageChecker.h" -#include "RefCountedCopyConstructorChecker.h" -#include "RefCountedInsideLambdaChecker.h" -#include "ScopeChecker.h" -#include "SprintfLiteralChecker.h" -#include "TrivialCtorDtorChecker.h" +#include "ChecksIncludes.inc" class DiagnosticsMatcher { public: DiagnosticsMatcher(); ASTConsumerPtr makeASTConsumer() { return AstMatcher.newASTConsumer(); } private: - ScopeChecker Scope; - ArithmeticArgChecker ArithmeticArg; - TrivialCtorDtorChecker TrivialCtorDtor; - NaNExprChecker NaNExpr; - NoAddRefReleaseOnReturnChecker NoAddRefReleaseOnReturn; - RefCountedInsideLambdaChecker RefCountedInsideLambda; - ExplicitOperatorBoolChecker ExplicitOperatorBool; - NoDuplicateRefCntMemberChecker NoDuplicateRefCntMember; - NeedsNoVTableTypeChecker NeedsNoVTableType; - NonMemMovableTemplateArgChecker NonMemMovableTemplateArg; - NonMemMovableMemberChecker NonMemMovableMember; - ExplicitImplicitChecker ExplicitImplicit; - NoAutoTypeChecker NoAutoType; - NoExplicitMoveConstructorChecker NoExplicitMoveConstructor; - RefCountedCopyConstructorChecker RefCountedCopyConstructor; - AssertAssignmentChecker AssertAssignment; - KungFuDeathGripChecker KungFuDeathGrip; - SprintfLiteralChecker SprintfLiteral; - OverrideBaseCallChecker OverrideBaseCall; - OverrideBaseCallUsageChecker OverrideBaseCallUsage; - NonParamInsideFunctionDeclChecker NonParamInsideFunctionDecl; +#define CHECK(cls, name) cls cls ## _; +#include "Checks.inc" +#undef CHECK MatchFinder AstMatcher; }; #endif
--- a/build/clang-plugin/ExplicitImplicitChecker.cpp +++ b/build/clang-plugin/ExplicitImplicitChecker.cpp @@ -1,36 +1,31 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ExplicitImplicitChecker.h" #include "CustomMatchers.h" -void ExplicitImplicitChecker::registerMatcher(MatchFinder& AstMatcher) { - AstMatcher.addMatcher(cxxConstructorDecl(isInterestingImplicitCtor(), - ofClass(allOf(isConcreteClass(), - decl().bind("class"))), - unless(isMarkedImplicit())) +void ExplicitImplicitChecker::registerMatchers(MatchFinder* AstMatcher) { + AstMatcher->addMatcher(cxxConstructorDecl(isInterestingImplicitCtor(), + ofClass(allOf(isConcreteClass(), + decl().bind("class"))), + unless(isMarkedImplicit())) .bind("ctor"), this); } -void ExplicitImplicitChecker::run( +void ExplicitImplicitChecker::check( const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "bad implicit conversion constructor for %0"); - unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, - "consider adding the explicit keyword to the constructor"); - // We've already checked everything in the matcher, so we just have to report // the error. const CXXConstructorDecl *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor"); const CXXRecordDecl *Declaration = Result.Nodes.getNodeAs<CXXRecordDecl>("class"); - Diag.Report(Ctor->getLocation(), ErrorID) << Declaration->getDeclName(); - Diag.Report(Ctor->getLocation(), NoteID); + diag(Ctor->getLocation(), "bad implicit conversion constructor for %0", + DiagnosticIDs::Error) << Declaration->getDeclName(); + diag(Ctor->getLocation(), "consider adding the explicit keyword to the constructor", + DiagnosticIDs::Note); }
--- a/build/clang-plugin/ExplicitImplicitChecker.h +++ b/build/clang-plugin/ExplicitImplicitChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef ExplicitImplicitChecker_h__ #define ExplicitImplicitChecker_h__ #include "plugin.h" -class ExplicitImplicitChecker : public MatchFinder::MatchCallback { +class ExplicitImplicitChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + ExplicitImplicitChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
--- a/build/clang-plugin/ExplicitOperatorBoolChecker.cpp +++ b/build/clang-plugin/ExplicitOperatorBoolChecker.cpp @@ -1,36 +1,33 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ExplicitOperatorBoolChecker.h" #include "CustomMatchers.h" -void ExplicitOperatorBoolChecker::registerMatcher(MatchFinder& AstMatcher) { +void ExplicitOperatorBoolChecker::registerMatchers(MatchFinder* AstMatcher) { // Older clang versions such as the ones used on the infra recognize these // conversions as 'operator _Bool', but newer clang versions recognize these // as 'operator bool'. - AstMatcher.addMatcher( + AstMatcher->addMatcher( cxxMethodDecl(anyOf(hasName("operator bool"), hasName("operator _Bool"))) .bind("node"), this); } -void ExplicitOperatorBoolChecker::run( +void ExplicitOperatorBoolChecker::check( const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "bad implicit conversion operator for %0"); - unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, "consider adding the explicit keyword to %0"); const CXXConversionDecl *Method = Result.Nodes.getNodeAs<CXXConversionDecl>("node"); const CXXRecordDecl *Clazz = Method->getParent(); if (!Method->isExplicitSpecified() && !MozChecker::hasCustomAnnotation(Method, "moz_implicit") && !ASTIsInSystemHeader(Method->getASTContext(), *Method) && isInterestingDeclForImplicitConversion(Method)) { - Diag.Report(Method->getLocStart(), ErrorID) << Clazz; - Diag.Report(Method->getLocStart(), NoteID) << "'operator bool'"; + diag(Method->getLocStart(), "bad implicit conversion operator for %0", + DiagnosticIDs::Error) << Clazz; + diag(Method->getLocStart(), "consider adding the explicit keyword to %0", + DiagnosticIDs::Note) << "'operator bool'"; } }
--- a/build/clang-plugin/ExplicitOperatorBoolChecker.h +++ b/build/clang-plugin/ExplicitOperatorBoolChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef ExplicitOperatorBoolChecker_h__ #define ExplicitOperatorBoolChecker_h__ #include "plugin.h" -class ExplicitOperatorBoolChecker : public MatchFinder::MatchCallback { +class ExplicitOperatorBoolChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + ExplicitOperatorBoolChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
--- a/build/clang-plugin/KungFuDeathGripChecker.cpp +++ b/build/clang-plugin/KungFuDeathGripChecker.cpp @@ -1,30 +1,26 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "KungFuDeathGripChecker.h" #include "CustomMatchers.h" -void KungFuDeathGripChecker::registerMatcher(MatchFinder& AstMatcher) { - AstMatcher.addMatcher(varDecl(hasType(isRefPtr())).bind("decl"), - this); +void KungFuDeathGripChecker::registerMatchers(MatchFinder* AstMatcher) { + AstMatcher->addMatcher(varDecl(hasType(isRefPtr())).bind("decl"), + this); } -void KungFuDeathGripChecker::run( +void KungFuDeathGripChecker::check( const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, - "Unused \"kungFuDeathGrip\" %0 objects constructed from %1 are prohibited"); - - unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, - "Please switch all accesses to this %0 to go through '%1', or explicitly pass '%1' to `mozilla::Unused`"); + const char* Error = + "Unused \"kungFuDeathGrip\" %0 objects constructed from %1 are prohibited"; + const char* Note = + "Please switch all accesses to this %0 to go through '%1', or explicitly pass '%1' to `mozilla::Unused`"; const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>("decl"); if (D->isReferenced() || !D->hasLocalStorage() || !D->hasInit()) { return; } // Not interested in parameters. if (isa<ImplicitParamDecl>(D) || isa<ParmVarDecl>(D)) { @@ -92,11 +88,11 @@ void KungFuDeathGripChecker::run( ErrThing = "members"; NoteThing = "member"; } else { ErrThing = "temporary values"; NoteThing = "value"; } // We cannot provide the note if we don't have an initializer - Diag.Report(D->getLocStart(), ErrorID) << D->getType() << ErrThing; - Diag.Report(E->getLocStart(), NoteID) << NoteThing << getNameChecked(D); + diag(D->getLocStart(), Error, DiagnosticIDs::Error) << D->getType() << ErrThing; + diag(E->getLocStart(), Note, DiagnosticIDs::Note) << NoteThing << getNameChecked(D); }
--- a/build/clang-plugin/KungFuDeathGripChecker.h +++ b/build/clang-plugin/KungFuDeathGripChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef KungFuDeathGripChecker_h__ #define KungFuDeathGripChecker_h__ #include "plugin.h" -class KungFuDeathGripChecker : public MatchFinder::MatchCallback { +class KungFuDeathGripChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + KungFuDeathGripChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
new file mode 100644 --- /dev/null +++ b/build/clang-plugin/MozillaTidyModule.cpp @@ -0,0 +1,37 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifdef CLANG_TIDY + +#include "../ClangTidy.h" +#include "../ClangTidyModule.h" +#include "../ClangTidyModuleRegistry.h" +#include "ChecksIncludes.inc" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { + +class MozillaModule : public ClangTidyModule { +public: + void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { +#define CHECK(cls, name) CheckFactories.registerCheck<cls>("mozilla-" name); +#include "Checks.inc" +#undef CHECK + } +}; + +// Register the MozillaTidyModule using this statically initialized variable. +static ClangTidyModuleRegistry::Add<MozillaModule> X("mozilla-module", + "Adds Mozilla lint checks."); + +} // namespace tidy +} // namespace clang + +// This anchor is used to force the linker to link in the generated object file +// and thus register the MozillaModule. +volatile int MozillaModuleAnchorSource = 0; + +#endif
--- a/build/clang-plugin/NaNExprChecker.cpp +++ b/build/clang-plugin/NaNExprChecker.cpp @@ -1,42 +1,36 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "NaNExprChecker.h" #include "CustomMatchers.h" -void NaNExprChecker::registerMatcher(MatchFinder& AstMatcher) { - AstMatcher.addMatcher( +void NaNExprChecker::registerMatchers(MatchFinder* AstMatcher) { + AstMatcher->addMatcher( binaryOperator( allOf(binaryEqualityOperator(), hasLHS(hasIgnoringParenImpCasts( declRefExpr(hasType(qualType((isFloat())))).bind("lhs"))), hasRHS(hasIgnoringParenImpCasts( declRefExpr(hasType(qualType((isFloat())))).bind("rhs"))), unless(anyOf(isInSystemHeader(), isInWhitelistForNaNExpr())))) .bind("node"), this); } -void NaNExprChecker::run( +void NaNExprChecker::check( const MatchFinder::MatchResult &Result) { if (!Result.Context->getLangOpts().CPlusPlus) { // mozilla::IsNaN is not usable in C, so there is no point in issuing these // warnings. return; } - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "comparing a floating point value to itself for " - "NaN checking can lead to incorrect results"); - unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, "consider using mozilla::IsNaN instead"); const BinaryOperator *Expression = Result.Nodes.getNodeAs<BinaryOperator>( "node"); const DeclRefExpr *LHS = Result.Nodes.getNodeAs<DeclRefExpr>("lhs"); const DeclRefExpr *RHS = Result.Nodes.getNodeAs<DeclRefExpr>("rhs"); const ImplicitCastExpr *LHSExpr = dyn_cast<ImplicitCastExpr>( Expression->getLHS()); const ImplicitCastExpr *RHSExpr = dyn_cast<ImplicitCastExpr>( Expression->getRHS()); @@ -48,12 +42,15 @@ void NaNExprChecker::run( // |-DeclRefExpr // The check below ensures that we are dealing with the correct AST subtree // shape, and // also that both of the found DeclRefExpr's point to the same declaration. if (LHS->getFoundDecl() == RHS->getFoundDecl() && LHSExpr && RHSExpr && std::distance(LHSExpr->child_begin(), LHSExpr->child_end()) == 1 && std::distance(RHSExpr->child_begin(), RHSExpr->child_end()) == 1 && *LHSExpr->child_begin() == LHS && *RHSExpr->child_begin() == RHS) { - Diag.Report(Expression->getLocStart(), ErrorID); - Diag.Report(Expression->getLocStart(), NoteID); + diag(Expression->getLocStart(), "comparing a floating point value to itself for " + "NaN checking can lead to incorrect results", + DiagnosticIDs::Error); + diag(Expression->getLocStart(), "consider using mozilla::IsNaN instead", + DiagnosticIDs::Note); } }
--- a/build/clang-plugin/NaNExprChecker.h +++ b/build/clang-plugin/NaNExprChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef NaNExprChecker_h__ #define NaNExprChecker_h__ #include "plugin.h" -class NaNExprChecker : public MatchFinder::MatchCallback { +class NaNExprChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + NaNExprChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
--- a/build/clang-plugin/NeedsNoVTableTypeChecker.cpp +++ b/build/clang-plugin/NeedsNoVTableTypeChecker.cpp @@ -1,44 +1,40 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "NeedsNoVTableTypeChecker.h" #include "CustomMatchers.h" -void NeedsNoVTableTypeChecker::registerMatcher(MatchFinder& AstMatcher) { - AstMatcher.addMatcher( +void NeedsNoVTableTypeChecker::registerMatchers(MatchFinder* AstMatcher) { + AstMatcher->addMatcher( classTemplateSpecializationDecl( allOf(hasAnyTemplateArgument(refersToType(hasVTable())), hasNeedsNoVTableTypeAttr())) .bind("node"), this); } -void NeedsNoVTableTypeChecker::run( +void NeedsNoVTableTypeChecker::check( const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, - "%0 cannot be instantiated because %1 has a VTable"); - unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, "bad instantiation of %0 requested here"); - const ClassTemplateSpecializationDecl *Specialization = Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("node"); // Get the offending template argument QualType Offender; const TemplateArgumentList &Args = Specialization->getTemplateInstantiationArgs(); for (unsigned i = 0; i < Args.size(); ++i) { Offender = Args[i].getAsType(); if (typeHasVTable(Offender)) { break; } } - Diag.Report(Specialization->getLocStart(), ErrorID) << Specialization - << Offender; - Diag.Report(Specialization->getPointOfInstantiation(), NoteID) - << Specialization; + diag(Specialization->getLocStart(), + "%0 cannot be instantiated because %1 has a VTable", + DiagnosticIDs::Error) << Specialization + << Offender; + diag(Specialization->getPointOfInstantiation(), + "bad instantiation of %0 requested here", + DiagnosticIDs::Note) << Specialization; }
--- a/build/clang-plugin/NeedsNoVTableTypeChecker.h +++ b/build/clang-plugin/NeedsNoVTableTypeChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef NeedsNoVTableTypeChecker_h__ #define NeedsNoVTableTypeChecker_h__ #include "plugin.h" -class NeedsNoVTableTypeChecker : public MatchFinder::MatchCallback { +class NeedsNoVTableTypeChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + NeedsNoVTableTypeChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
--- a/build/clang-plugin/NoAddRefReleaseOnReturnChecker.cpp +++ b/build/clang-plugin/NoAddRefReleaseOnReturnChecker.cpp @@ -1,41 +1,40 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "NoAddRefReleaseOnReturnChecker.h" #include "CustomMatchers.h" -void NoAddRefReleaseOnReturnChecker::registerMatcher(MatchFinder& AstMatcher) { +void NoAddRefReleaseOnReturnChecker::registerMatchers(MatchFinder* AstMatcher) { // First, look for direct parents of the MemberExpr. - AstMatcher.addMatcher( + AstMatcher->addMatcher( callExpr( callee(functionDecl(hasNoAddRefReleaseOnReturnAttr()).bind("func")), hasParent(memberExpr(isAddRefOrRelease(), hasParent(callExpr())) .bind("member"))) .bind("node"), this); // Then, look for MemberExpr that need to be casted to the right type using // an intermediary CastExpr before we get to the CallExpr. - AstMatcher.addMatcher( + AstMatcher->addMatcher( callExpr( callee(functionDecl(hasNoAddRefReleaseOnReturnAttr()).bind("func")), hasParent(castExpr( hasParent(memberExpr(isAddRefOrRelease(), hasParent(callExpr())) .bind("member"))))) .bind("node"), this); } -void NoAddRefReleaseOnReturnChecker::run( +void NoAddRefReleaseOnReturnChecker::check( const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "%1 cannot be called on the return value of %0"); const Stmt *Node = Result.Nodes.getNodeAs<Stmt>("node"); const FunctionDecl *Func = Result.Nodes.getNodeAs<FunctionDecl>("func"); const MemberExpr *Member = Result.Nodes.getNodeAs<MemberExpr>("member"); const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member->getMemberDecl()); - Diag.Report(Node->getLocStart(), ErrorID) << Func << Method; + diag(Node->getLocStart(), + "%1 cannot be called on the return value of %0", + DiagnosticIDs::Error) << Func << Method; }
--- a/build/clang-plugin/NoAddRefReleaseOnReturnChecker.h +++ b/build/clang-plugin/NoAddRefReleaseOnReturnChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef NoAddRefReleaseOnReturnChecker_h__ #define NoAddRefReleaseOnReturnChecker_h__ #include "plugin.h" -class NoAddRefReleaseOnReturnChecker : public MatchFinder::MatchCallback { +class NoAddRefReleaseOnReturnChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + NoAddRefReleaseOnReturnChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
--- a/build/clang-plugin/NoAutoTypeChecker.cpp +++ b/build/clang-plugin/NoAutoTypeChecker.cpp @@ -1,25 +1,23 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "NoAutoTypeChecker.h" #include "CustomMatchers.h" -void NoAutoTypeChecker::registerMatcher(MatchFinder& AstMatcher) { - AstMatcher.addMatcher(varDecl(hasType(autoNonAutoableType())).bind("node"), - this); +void NoAutoTypeChecker::registerMatchers(MatchFinder* AstMatcher) { + AstMatcher->addMatcher(varDecl(hasType(autoNonAutoableType())).bind("node"), + this); } -void NoAutoTypeChecker::run( +void NoAutoTypeChecker::check( const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "Cannot use auto to declare a variable of type %0"); - unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, "Please write out this type explicitly"); - const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>("node"); - Diag.Report(D->getLocation(), ErrorID) << D->getType(); - Diag.Report(D->getLocation(), NoteID); + diag(D->getLocation(), + "Cannot use auto to declare a variable of type %0", + DiagnosticIDs::Error) << D->getType(); + diag(D->getLocation(), + "Please write out this type explicitly", + DiagnosticIDs::Note); }
--- a/build/clang-plugin/NoAutoTypeChecker.h +++ b/build/clang-plugin/NoAutoTypeChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef NoAutoTypeChecker_h__ #define NoAutoTypeChecker_h__ #include "plugin.h" -class NoAutoTypeChecker : public MatchFinder::MatchCallback { +class NoAutoTypeChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + NoAutoTypeChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
--- a/build/clang-plugin/NoDuplicateRefCntMemberChecker.cpp +++ b/build/clang-plugin/NoDuplicateRefCntMemberChecker.cpp @@ -1,22 +1,21 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "NoDuplicateRefCntMemberChecker.h" #include "CustomMatchers.h" -void NoDuplicateRefCntMemberChecker::registerMatcher(MatchFinder& AstMatcher) { - AstMatcher.addMatcher(cxxRecordDecl().bind("decl"), this); +void NoDuplicateRefCntMemberChecker::registerMatchers(MatchFinder* AstMatcher) { + AstMatcher->addMatcher(cxxRecordDecl().bind("decl"), this); } -void NoDuplicateRefCntMemberChecker::run( +void NoDuplicateRefCntMemberChecker::check( const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); const CXXRecordDecl *D = Result.Nodes.getNodeAs<CXXRecordDecl>("decl"); const FieldDecl *RefCntMember = getClassRefCntMember(D); const FieldDecl *FoundRefCntBase = nullptr; if (!D->hasDefinition()) return; D = D->getDefinition(); @@ -30,44 +29,40 @@ void NoDuplicateRefCntMemberChecker::run // warn for those which do for (auto &Base : D->bases()) { // Determine if this base class has an mRefCnt member const FieldDecl *BaseRefCntMember = getBaseRefCntMember(Base.getType()); if (BaseRefCntMember) { if (RefCntMember) { // We have an mRefCnt, and superclass has an mRefCnt - unsigned Error = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, - "Refcounted record %0 has multiple mRefCnt members"); - unsigned Note1 = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, "Superclass %0 also has an mRefCnt member"); - unsigned Note2 = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, - "Consider using the _INHERITED macros for AddRef and Release here"); + const char* Error = + "Refcounted record %0 has multiple mRefCnt members"; + const char* Note1 = + "Superclass %0 also has an mRefCnt member"; + const char* Note2 = + "Consider using the _INHERITED macros for AddRef and Release here"; - Diag.Report(D->getLocStart(), Error) << D; - Diag.Report(BaseRefCntMember->getLocStart(), Note1) + diag(D->getLocStart(), Error, DiagnosticIDs::Error) << D; + diag(BaseRefCntMember->getLocStart(), Note1, DiagnosticIDs::Note) << BaseRefCntMember->getParent(); - Diag.Report(RefCntMember->getLocStart(), Note2); + diag(RefCntMember->getLocStart(), Note2, DiagnosticIDs::Note); } if (FoundRefCntBase) { - unsigned Error = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, - "Refcounted record %0 has multiple superclasses with mRefCnt members"); - unsigned Note = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, - "Superclass %0 has an mRefCnt member"); + const char* Error = + "Refcounted record %0 has multiple superclasses with mRefCnt members"; + const char* Note = + "Superclass %0 has an mRefCnt member"; // superclass has mRefCnt, and another superclass also has an mRefCnt - Diag.Report(D->getLocStart(), Error) << D; - Diag.Report(BaseRefCntMember->getLocStart(), Note) + diag(D->getLocStart(), Error, DiagnosticIDs::Error) << D; + diag(BaseRefCntMember->getLocStart(), Note, DiagnosticIDs::Note) << BaseRefCntMember->getParent(); - Diag.Report(FoundRefCntBase->getLocStart(), Note) + diag(FoundRefCntBase->getLocStart(), Note, DiagnosticIDs::Note) << FoundRefCntBase->getParent(); } // Record that we've found a base with a mRefCnt member FoundRefCntBase = BaseRefCntMember; } } }
--- a/build/clang-plugin/NoDuplicateRefCntMemberChecker.h +++ b/build/clang-plugin/NoDuplicateRefCntMemberChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef NoDuplicateRefCntMemberChecker_h__ #define NoDuplicateRefCntMemberChecker_h__ #include "plugin.h" -class NoDuplicateRefCntMemberChecker : public MatchFinder::MatchCallback { +class NoDuplicateRefCntMemberChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + NoDuplicateRefCntMemberChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
--- a/build/clang-plugin/NoExplicitMoveConstructorChecker.cpp +++ b/build/clang-plugin/NoExplicitMoveConstructorChecker.cpp @@ -1,26 +1,23 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "NoExplicitMoveConstructorChecker.h" #include "CustomMatchers.h" -void NoExplicitMoveConstructorChecker::registerMatcher(MatchFinder& AstMatcher) { - AstMatcher.addMatcher( +void NoExplicitMoveConstructorChecker::registerMatchers(MatchFinder* AstMatcher) { + AstMatcher->addMatcher( cxxConstructorDecl(isExplicitMoveConstructor()).bind("node"), this); } -void NoExplicitMoveConstructorChecker::run( +void NoExplicitMoveConstructorChecker::check( const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "Move constructors may not be marked explicit"); - // Everything we needed to know was checked in the matcher - we just report // the error here const CXXConstructorDecl *D = Result.Nodes.getNodeAs<CXXConstructorDecl>("node"); - Diag.Report(D->getLocation(), ErrorID); + diag(D->getLocation(), "Move constructors may not be marked explicit", + DiagnosticIDs::Error); }
--- a/build/clang-plugin/NoExplicitMoveConstructorChecker.h +++ b/build/clang-plugin/NoExplicitMoveConstructorChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef NoExplicitMoveConstructorChecker_h__ #define NoExplicitMoveConstructorChecker_h__ #include "plugin.h" -class NoExplicitMoveConstructorChecker : public MatchFinder::MatchCallback { +class NoExplicitMoveConstructorChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + NoExplicitMoveConstructorChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
--- a/build/clang-plugin/NonMemMovableMemberChecker.cpp +++ b/build/clang-plugin/NonMemMovableMemberChecker.cpp @@ -2,38 +2,37 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "NonMemMovableMemberChecker.h" #include "CustomMatchers.h" MemMoveAnnotation NonMemMovable = MemMoveAnnotation(); -void NonMemMovableMemberChecker::registerMatcher(MatchFinder& AstMatcher) { +void NonMemMovableMemberChecker::registerMatchers(MatchFinder* AstMatcher) { // Handle non-mem-movable members - AstMatcher.addMatcher( + AstMatcher->addMatcher( cxxRecordDecl(needsMemMovableMembers()) .bind("decl"), this); } -void NonMemMovableMemberChecker::run( +void NonMemMovableMemberChecker::check( const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, - "class %0 cannot have non-memmovable member %1 of type %2"); + const char* Error = + "class %0 cannot have non-memmovable member %1 of type %2"; // Get the specialization const CXXRecordDecl* Declaration = Result.Nodes.getNodeAs<CXXRecordDecl>("decl"); // Report an error for every member which is non-memmovable for (const FieldDecl *Field : Declaration->fields()) { QualType Type = Field->getType(); if (NonMemMovable.hasEffectiveAnnotation(Type)) { - Diag.Report(Field->getLocation(), ErrorID) << Declaration - << Field - << Type; - NonMemMovable.dumpAnnotationReason(Diag, Type, Declaration->getLocation()); + diag(Field->getLocation(), Error, DiagnosticIDs::Error) + << Declaration + << Field + << Type; + NonMemMovable.dumpAnnotationReason(*this, Type, Declaration->getLocation()); } } }
--- a/build/clang-plugin/NonMemMovableMemberChecker.h +++ b/build/clang-plugin/NonMemMovableMemberChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef NonMemMovableMemberChecker_h__ #define NonMemMovableMemberChecker_h__ #include "plugin.h" -class NonMemMovableMemberChecker : public MatchFinder::MatchCallback { +class NonMemMovableMemberChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + NonMemMovableMemberChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
--- a/build/clang-plugin/NonMemMovableTemplateArgChecker.cpp +++ b/build/clang-plugin/NonMemMovableTemplateArgChecker.cpp @@ -1,53 +1,52 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "NonMemMovableTemplateArgChecker.h" #include "CustomMatchers.h" -void NonMemMovableTemplateArgChecker::registerMatcher(MatchFinder& AstMatcher) { +void NonMemMovableTemplateArgChecker::registerMatchers(MatchFinder* AstMatcher) { // Handle non-mem-movable template specializations - AstMatcher.addMatcher( + AstMatcher->addMatcher( classTemplateSpecializationDecl( allOf(needsMemMovableTemplateArg(), hasAnyTemplateArgument(refersToType(isNonMemMovable())))) .bind("specialization"), this); } -void NonMemMovableTemplateArgChecker::run( +void NonMemMovableTemplateArgChecker::check( const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, - "Cannot instantiate %0 with non-memmovable template argument %1"); - unsigned Note1ID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, "instantiation of %0 requested here"); + const char* Error = + "Cannot instantiate %0 with non-memmovable template argument %1"; + const char* Note = + "instantiation of %0 requested here"; // Get the specialization const ClassTemplateSpecializationDecl *Specialization = Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("specialization"); SourceLocation RequestLoc = Specialization->getPointOfInstantiation(); // Report an error for every template argument which is non-memmovable const TemplateArgumentList &Args = Specialization->getTemplateInstantiationArgs(); for (unsigned i = 0; i < Args.size(); ++i) { QualType ArgType = Args[i].getAsType(); if (NonMemMovable.hasEffectiveAnnotation(ArgType)) { - Diag.Report(Specialization->getLocation(), ErrorID) << Specialization - << ArgType; + diag(Specialization->getLocation(), Error, + DiagnosticIDs::Error) << Specialization + << ArgType; // XXX It would be really nice if we could get the instantiation stack // information // from Sema such that we could print a full template instantiation stack, // however, // it seems as though that information is thrown out by the time we get // here so we // can only report one level of template specialization (which in many // cases won't // be useful) - Diag.Report(RequestLoc, Note1ID) << Specialization; - NonMemMovable.dumpAnnotationReason(Diag, ArgType, RequestLoc); + diag(RequestLoc, Note, DiagnosticIDs::Note) << Specialization; + NonMemMovable.dumpAnnotationReason(*this, ArgType, RequestLoc); } } }
--- a/build/clang-plugin/NonMemMovableTemplateArgChecker.h +++ b/build/clang-plugin/NonMemMovableTemplateArgChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef NonMemMovableTemplateArgChecker_h__ #define NonMemMovableTemplateArgChecker_h__ #include "plugin.h" -class NonMemMovableTemplateArgChecker : public MatchFinder::MatchCallback { +class NonMemMovableTemplateArgChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + NonMemMovableTemplateArgChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
--- a/build/clang-plugin/NonParamInsideFunctionDeclChecker.cpp +++ b/build/clang-plugin/NonParamInsideFunctionDeclChecker.cpp @@ -1,29 +1,29 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "NonParamInsideFunctionDeclChecker.h" #include "CustomMatchers.h" -void NonParamInsideFunctionDeclChecker::registerMatcher(MatchFinder& AstMatcher) { - AstMatcher.addMatcher( +void NonParamInsideFunctionDeclChecker::registerMatchers(MatchFinder* AstMatcher) { + AstMatcher->addMatcher( functionDecl(anyOf(allOf(isDefinition(), hasAncestor(classTemplateSpecializationDecl() .bind("spec"))), isDefinition())) .bind("func"), this); - AstMatcher.addMatcher( + AstMatcher->addMatcher( lambdaExpr().bind("lambda"), this); } -void NonParamInsideFunctionDeclChecker::run( +void NonParamInsideFunctionDeclChecker::check( const MatchFinder::MatchResult &Result) { static DenseSet<const FunctionDecl*> CheckedFunctionDecls; const FunctionDecl *func = Result.Nodes.getNodeAs<FunctionDecl>("func"); if (!func) { const LambdaExpr *lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda"); if (lambda) { func = lambda->getCallOperator(); @@ -42,29 +42,25 @@ void NonParamInsideFunctionDeclChecker:: if (CheckedFunctionDecls.count(func)) { return; } CheckedFunctionDecls.insert(func); const ClassTemplateSpecializationDecl *Spec = Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("spec"); - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "Type %0 must not be used as parameter"); - unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, "Please consider passing a const reference instead"); - unsigned SpecNoteID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, "The bad argument was passed to %0 here"); - for (ParmVarDecl *p : func->parameters()) { QualType T = p->getType().withoutLocalFastQualifiers(); if (NonParam.hasEffectiveAnnotation(T)) { - Diag.Report(p->getLocation(), ErrorID) << T; - Diag.Report(p->getLocation(), NoteID); + diag(p->getLocation(), "Type %0 must not be used as parameter", + DiagnosticIDs::Error) << T; + diag(p->getLocation(), "Please consider passing a const reference instead", + DiagnosticIDs::Note); if (Spec) { - Diag.Report(Spec->getPointOfInstantiation(), SpecNoteID) + diag(Spec->getPointOfInstantiation(), + "The bad argument was passed to %0 here", + DiagnosticIDs::Note) << Spec->getSpecializedTemplate(); } } } }
--- a/build/clang-plugin/NonParamInsideFunctionDeclChecker.h +++ b/build/clang-plugin/NonParamInsideFunctionDeclChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef NonParamInsideFunctionDeclChecker_h__ #define NonParamInsideFunctionDeclChecker_h__ #include "plugin.h" -class NonParamInsideFunctionDeclChecker : public MatchFinder::MatchCallback { +class NonParamInsideFunctionDeclChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + NonParamInsideFunctionDeclChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
--- a/build/clang-plugin/OverrideBaseCallChecker.cpp +++ b/build/clang-plugin/OverrideBaseCallChecker.cpp @@ -1,17 +1,17 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "OverrideBaseCallChecker.h" #include "CustomMatchers.h" -void OverrideBaseCallChecker::registerMatcher(MatchFinder& AstMatcher) { - AstMatcher.addMatcher(cxxRecordDecl(hasBaseClasses()).bind("class"), +void OverrideBaseCallChecker::registerMatchers(MatchFinder* AstMatcher) { + AstMatcher->addMatcher(cxxRecordDecl(hasBaseClasses()).bind("class"), this); } bool OverrideBaseCallChecker::isRequiredBaseMethod( const CXXMethodDecl *Method) { return MozChecker::hasCustomAnnotation(Method, "moz_required_base_method"); } @@ -58,23 +58,21 @@ void OverrideBaseCallChecker::findBaseMe MethodsList.remove(Method); // Loop also through all it's base methods; for (auto BaseMethod = Method->begin_overridden_methods(); BaseMethod != Method->end_overridden_methods(); BaseMethod++) { findBaseMethodCall(*BaseMethod, MethodsList); } } -void OverrideBaseCallChecker::run( +void OverrideBaseCallChecker::check( const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned OverrideBaseCallCheckID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, + const char* Error = "Method %0 must be called in all overrides, but is not called in " - "this override defined for class %1"); + "this override defined for class %1"; const CXXRecordDecl *Decl = Result.Nodes.getNodeAs<CXXRecordDecl>("class"); // Loop through the methods and look for the ones that are overridden. for (auto Method : Decl->methods()) { // If this method doesn't override other methods or it doesn't have a body, // continue to the next declaration. if (!Method->size_overridden_methods() || !Method->hasBody()) { continue; @@ -97,14 +95,14 @@ void OverrideBaseCallChecker::run( } // Loop through the body of our method and search for calls to // base methods evaluateExpression(Method->getBody(), MethodsList); // If list is not empty pop up errors for (auto BaseMethod : MethodsList) { - Diag.Report(Method->getLocation(), OverrideBaseCallCheckID) + diag(Method->getLocation(), Error, DiagnosticIDs::Error) << BaseMethod->getQualifiedNameAsString() << Decl->getName(); } } }
--- a/build/clang-plugin/OverrideBaseCallChecker.h +++ b/build/clang-plugin/OverrideBaseCallChecker.h @@ -2,20 +2,23 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef OverrideBaseCallChecker_h__ #define OverrideBaseCallChecker_h__ #include "plugin.h" -class OverrideBaseCallChecker : public MatchFinder::MatchCallback { +class OverrideBaseCallChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + OverrideBaseCallChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; private: void evaluateExpression(const Stmt *StmtExpr, std::list<const CXXMethodDecl*> &MethodList); void getRequiredBaseMethod(const CXXMethodDecl* Method, std::list<const CXXMethodDecl*>& MethodsList); void findBaseMethodCall(const CXXMethodDecl* Method, std::list<const CXXMethodDecl*>& MethodsList); bool isRequiredBaseMethod(const CXXMethodDecl *Method);
--- a/build/clang-plugin/OverrideBaseCallUsageChecker.cpp +++ b/build/clang-plugin/OverrideBaseCallUsageChecker.cpp @@ -1,23 +1,21 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "OverrideBaseCallUsageChecker.h" #include "CustomMatchers.h" -void OverrideBaseCallUsageChecker::registerMatcher(MatchFinder& AstMatcher) { - AstMatcher.addMatcher( +void OverrideBaseCallUsageChecker::registerMatchers(MatchFinder* AstMatcher) { + AstMatcher->addMatcher( cxxMethodDecl(isNonVirtual(), isRequiredBaseMethod()).bind("method"), this); } -void OverrideBaseCallUsageChecker::run( +void OverrideBaseCallUsageChecker::check( const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, - "MOZ_REQUIRED_BASE_METHOD can be used only on virtual methods"); + const char* Error = + "MOZ_REQUIRED_BASE_METHOD can be used only on virtual methods"; const CXXMethodDecl *Method = Result.Nodes.getNodeAs<CXXMethodDecl>("method"); - Diag.Report(Method->getLocation(), ErrorID); + diag(Method->getLocation(), Error, DiagnosticIDs::Error); }
--- a/build/clang-plugin/OverrideBaseCallUsageChecker.h +++ b/build/clang-plugin/OverrideBaseCallUsageChecker.h @@ -6,15 +6,18 @@ #define OverrideBaseCallUsageChecker_h__ #include "plugin.h" /* * This is a companion checker for OverrideBaseCallChecker that rejects * the usage of MOZ_REQUIRED_BASE_METHOD on non-virtual base methods. */ -class OverrideBaseCallUsageChecker : public MatchFinder::MatchCallback { +class OverrideBaseCallUsageChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + OverrideBaseCallUsageChecker(StringRef CheckName = "override-base-call-usage", + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
--- a/build/clang-plugin/RefCountedCopyConstructorChecker.cpp +++ b/build/clang-plugin/RefCountedCopyConstructorChecker.cpp @@ -1,37 +1,34 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "RefCountedCopyConstructorChecker.h" #include "CustomMatchers.h" -void RefCountedCopyConstructorChecker::registerMatcher(MatchFinder& AstMatcher) { - AstMatcher.addMatcher( +void RefCountedCopyConstructorChecker::registerMatchers(MatchFinder* AstMatcher) { + AstMatcher->addMatcher( cxxConstructExpr( hasDeclaration(cxxConstructorDecl(isCompilerProvidedCopyConstructor(), ofClass(hasRefCntMember())))) .bind("node"), this); } -void RefCountedCopyConstructorChecker::run( +void RefCountedCopyConstructorChecker::check( const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "Invalid use of compiler-provided copy constructor " - "on refcounted type"); - unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, + const char* Error = + "Invalid use of compiler-provided copy constructor on refcounted type"; + const char* Note = "The default copy constructor also copies the " "default mRefCnt property, leading to reference " "count imbalance issues. Please provide your own " "copy constructor which only copies the fields which " - "need to be copied"); + "need to be copied"; // Everything we needed to know was checked in the matcher - we just report // the error here const CXXConstructExpr *E = Result.Nodes.getNodeAs<CXXConstructExpr>("node"); - Diag.Report(E->getLocation(), ErrorID); - Diag.Report(E->getLocation(), NoteID); + diag(E->getLocation(), Error, DiagnosticIDs::Error); + diag(E->getLocation(), Note, DiagnosticIDs::Note); }
--- a/build/clang-plugin/RefCountedCopyConstructorChecker.h +++ b/build/clang-plugin/RefCountedCopyConstructorChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef RefCountedCopyConstructorChecker_h__ #define RefCountedCopyConstructorChecker_h__ #include "plugin.h" -class RefCountedCopyConstructorChecker : public MatchFinder::MatchCallback { +class RefCountedCopyConstructorChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + RefCountedCopyConstructorChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
--- a/build/clang-plugin/RefCountedInsideLambdaChecker.cpp +++ b/build/clang-plugin/RefCountedInsideLambdaChecker.cpp @@ -2,47 +2,45 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "RefCountedInsideLambdaChecker.h" #include "CustomMatchers.h" RefCountedMap RefCountedClasses; -void RefCountedInsideLambdaChecker::registerMatcher(MatchFinder& AstMatcher) { +void RefCountedInsideLambdaChecker::registerMatchers(MatchFinder* AstMatcher) { // We want to reject any code which captures a pointer to an object of a // refcounted type, and then lets that value escape. As a primitive analysis, // we reject any occurances of the lambda as a template parameter to a class // (which could allow it to escape), as well as any presence of such a lambda // in a return value (either from lambdas, or in c++14, auto functions). // // We check these lambdas' capture lists for raw pointers to refcounted types. - AstMatcher.addMatcher( + AstMatcher->addMatcher( functionDecl(returns(recordType(hasDeclaration(cxxRecordDecl( isLambdaDecl()).bind("decl"))))), this); - AstMatcher.addMatcher(lambdaExpr().bind("lambdaExpr"), + AstMatcher->addMatcher(lambdaExpr().bind("lambdaExpr"), this); - AstMatcher.addMatcher( + AstMatcher->addMatcher( classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType( recordType(hasDeclaration(cxxRecordDecl( isLambdaDecl()).bind("decl")))))), this); } -void RefCountedInsideLambdaChecker::run( +void RefCountedInsideLambdaChecker::check( const MatchFinder::MatchResult &Result) { static DenseSet<const CXXRecordDecl*> CheckedDecls; - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, - "Refcounted variable %0 of type %1 cannot be captured by a lambda"); - unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, "Please consider using a smart pointer"); + const char* Error = + "Refcounted variable %0 of type %1 cannot be captured by a lambda"; + const char* Note = + "Please consider using a smart pointer"; const CXXRecordDecl *Lambda = Result.Nodes.getNodeAs<CXXRecordDecl>("decl"); if (const LambdaExpr *OuterLambda = Result.Nodes.getNodeAs<LambdaExpr>("lambdaExpr")) { const CXXMethodDecl *OpCall = OuterLambda->getCallOperator(); QualType ReturnTy = OpCall->getReturnType(); if (const CXXRecordDecl *Record = ReturnTy->getAsCXXRecordDecl()) { @@ -60,16 +58,18 @@ void RefCountedInsideLambdaChecker::run( } CheckedDecls.insert(Lambda); for (const LambdaCapture Capture : Lambda->captures()) { if (Capture.capturesVariable() && Capture.getCaptureKind() != LCK_ByRef) { QualType Pointee = Capture.getCapturedVar()->getType()->getPointeeType(); if (!Pointee.isNull() && isClassRefCounted(Pointee)) { - Diag.Report(Capture.getLocation(), ErrorID) << Capture.getCapturedVar() - << Pointee; - Diag.Report(Capture.getLocation(), NoteID); + diag(Capture.getLocation(), Error, + DiagnosticIDs::Error) << Capture.getCapturedVar() + << Pointee; + diag(Capture.getLocation(), Note, + DiagnosticIDs::Note); return; } } } }
--- a/build/clang-plugin/RefCountedInsideLambdaChecker.h +++ b/build/clang-plugin/RefCountedInsideLambdaChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef RefCountedInsideLambdaChecker_h__ #define RefCountedInsideLambdaChecker_h__ #include "plugin.h" -class RefCountedInsideLambdaChecker : public MatchFinder::MatchCallback { +class RefCountedInsideLambdaChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + RefCountedInsideLambdaChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
--- a/build/clang-plugin/ScopeChecker.cpp +++ b/build/clang-plugin/ScopeChecker.cpp @@ -1,23 +1,23 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ScopeChecker.h" #include "CustomMatchers.h" -void ScopeChecker::registerMatcher(MatchFinder& AstMatcher) { - AstMatcher.addMatcher(varDecl().bind("node"), this); - AstMatcher.addMatcher(cxxNewExpr().bind("node"), this); - AstMatcher.addMatcher(materializeTemporaryExpr().bind("node"), this); - AstMatcher.addMatcher( +void ScopeChecker::registerMatchers(MatchFinder* AstMatcher) { + AstMatcher->addMatcher(varDecl().bind("node"), this); + AstMatcher->addMatcher(cxxNewExpr().bind("node"), this); + AstMatcher->addMatcher(materializeTemporaryExpr().bind("node"), this); + AstMatcher->addMatcher( callExpr(callee(functionDecl(heapAllocator()))).bind("node"), this); - AstMatcher.addMatcher(parmVarDecl().bind("parm_vardecl"), this); + AstMatcher->addMatcher(parmVarDecl().bind("parm_vardecl"), this); } // These enum variants determine whether an allocation has occured in the code. enum AllocationVariety { AV_None, AV_Global, AV_Automatic, AV_Temporary, @@ -26,20 +26,18 @@ enum AllocationVariety { // XXX Currently the Decl* in the AutomaticTemporaryMap is unused, but it // probably will be used at some point in the future, in order to produce better // error messages. typedef DenseMap<const MaterializeTemporaryExpr *, const Decl *> AutomaticTemporaryMap; AutomaticTemporaryMap AutomaticTemporaries; -void ScopeChecker::run( +void ScopeChecker::check( const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - // There are a variety of different reasons why something could be allocated AllocationVariety Variety = AV_None; SourceLocation Loc; QualType T; if (const ParmVarDecl *D = Result.Nodes.getNodeAs<ParmVarDecl>("parm_vardecl")) { if (D->hasUnparsedDefaultArg() || D->hasUninstantiatedDefaultArg()) { @@ -117,58 +115,57 @@ void ScopeChecker::run( // This will always allocate on the heap, as the heapAllocator() check // was made in the matcher Variety = AV_Heap; Loc = E->getLocStart(); } } // Error messages for incorrect allocations. - unsigned StackID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "variable of type %0 only valid on the stack"); - unsigned GlobalID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "variable of type %0 only valid as global"); - unsigned HeapID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "variable of type %0 only valid on the heap"); - unsigned NonHeapID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "variable of type %0 is not valid on the heap"); - unsigned NonTemporaryID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "variable of type %0 is not valid in a temporary"); + const char* Stack = + "variable of type %0 only valid on the stack"; + const char* Global = + "variable of type %0 only valid as global"; + const char* Heap = + "variable of type %0 only valid on the heap"; + const char* NonHeap = + "variable of type %0 is not valid on the heap"; + const char* NonTemporary = + "variable of type %0 is not valid in a temporary"; - unsigned StackNoteID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, - "value incorrectly allocated in an automatic variable"); - unsigned GlobalNoteID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, "value incorrectly allocated in a global variable"); - unsigned HeapNoteID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, "value incorrectly allocated on the heap"); - unsigned TemporaryNoteID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, "value incorrectly allocated in a temporary"); + const char* StackNote = + "value incorrectly allocated in an automatic variable"; + const char* GlobalNote = + "value incorrectly allocated in a global variable"; + const char* HeapNote = + "value incorrectly allocated on the heap"; + const char* TemporaryNote = + "value incorrectly allocated in a temporary"; // Report errors depending on the annotations on the input types. switch (Variety) { case AV_None: return; case AV_Global: - StackClass.reportErrorIfPresent(Diag, T, Loc, StackID, GlobalNoteID); - HeapClass.reportErrorIfPresent(Diag, T, Loc, HeapID, GlobalNoteID); + StackClass.reportErrorIfPresent(*this, T, Loc, Stack, GlobalNote); + HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, GlobalNote); break; case AV_Automatic: - GlobalClass.reportErrorIfPresent(Diag, T, Loc, GlobalID, StackNoteID); - HeapClass.reportErrorIfPresent(Diag, T, Loc, HeapID, StackNoteID); + GlobalClass.reportErrorIfPresent(*this, T, Loc, Global, StackNote); + HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, StackNote); break; case AV_Temporary: - GlobalClass.reportErrorIfPresent(Diag, T, Loc, GlobalID, TemporaryNoteID); - HeapClass.reportErrorIfPresent(Diag, T, Loc, HeapID, TemporaryNoteID); - NonTemporaryClass.reportErrorIfPresent(Diag, T, Loc, NonTemporaryID, - TemporaryNoteID); + GlobalClass.reportErrorIfPresent(*this, T, Loc, Global, TemporaryNote); + HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, TemporaryNote); + NonTemporaryClass.reportErrorIfPresent(*this, T, Loc, NonTemporary, + TemporaryNote); break; case AV_Heap: - GlobalClass.reportErrorIfPresent(Diag, T, Loc, GlobalID, HeapNoteID); - StackClass.reportErrorIfPresent(Diag, T, Loc, StackID, HeapNoteID); - NonHeapClass.reportErrorIfPresent(Diag, T, Loc, NonHeapID, HeapNoteID); + GlobalClass.reportErrorIfPresent(*this, T, Loc, Global, HeapNote); + StackClass.reportErrorIfPresent(*this, T, Loc, Stack, HeapNote); + NonHeapClass.reportErrorIfPresent(*this, T, Loc, NonHeap, HeapNote); break; } }
--- a/build/clang-plugin/ScopeChecker.h +++ b/build/clang-plugin/ScopeChecker.h @@ -2,15 +2,17 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef ScopeChecker_h__ #define ScopeChecker_h__ #include "plugin.h" -class ScopeChecker : public MatchFinder::MatchCallback { +class ScopeChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + ScopeChecker(StringRef CheckName, ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
--- a/build/clang-plugin/SprintfLiteralChecker.cpp +++ b/build/clang-plugin/SprintfLiteralChecker.cpp @@ -1,41 +1,40 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "SprintfLiteralChecker.h" #include "CustomMatchers.h" -void SprintfLiteralChecker::registerMatcher(MatchFinder& AstMatcher) { - AstMatcher.addMatcher( +void SprintfLiteralChecker::registerMatchers(MatchFinder* AstMatcher) { + AstMatcher->addMatcher( callExpr(isSnprintfLikeFunc(), allOf(hasArgument(0, ignoringParenImpCasts(declRefExpr().bind("buffer"))), anyOf(hasArgument(1, sizeOfExpr(hasIgnoringParenImpCasts(declRefExpr().bind("size")))), hasArgument(1, integerLiteral().bind("immediate")), hasArgument(1, declRefExpr(to(varDecl(hasType(isConstQualified()), hasInitializer(integerLiteral().bind("constant"))))))))) .bind("funcCall"), this ); } -void SprintfLiteralChecker::run( +void SprintfLiteralChecker::check( const MatchFinder::MatchResult &Result) { if (!Result.Context->getLangOpts().CPlusPlus) { // SprintfLiteral is not usable in C, so there is no point in issuing these // warnings. return; } - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, "Use %1 instead of %0 when writing into a character array."); - unsigned NoteID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Note, "This will prevent passing in the wrong size to %0 accidentally."); + const char* Error = + "Use %1 instead of %0 when writing into a character array."; + const char* Note = + "This will prevent passing in the wrong size to %0 accidentally."; const CallExpr *D = Result.Nodes.getNodeAs<CallExpr>("funcCall"); StringRef Name = D->getDirectCallee()->getName(); const char *Replacement; if (Name == "snprintf") { Replacement = "SprintfLiteral"; } else { @@ -46,29 +45,29 @@ void SprintfLiteralChecker::run( const DeclRefExpr *Buffer = Result.Nodes.getNodeAs<DeclRefExpr>("buffer"); const DeclRefExpr *Size = Result.Nodes.getNodeAs<DeclRefExpr>("size"); if (Size) { // Match calls like snprintf(x, sizeof(x), ...). if (Buffer->getFoundDecl() != Size->getFoundDecl()) { return; } - Diag.Report(D->getLocStart(), ErrorID) << Name << Replacement; - Diag.Report(D->getLocStart(), NoteID) << Name; + diag(D->getLocStart(), Error, DiagnosticIDs::Error) << Name << Replacement; + diag(D->getLocStart(), Note, DiagnosticIDs::Note) << Name; return; } const QualType QType = Buffer->getType(); const ConstantArrayType *Type = dyn_cast<ConstantArrayType>(QType.getTypePtrOrNull()); if (Type) { // Match calls like snprintf(x, 100, ...), where x is int[100]; const IntegerLiteral *Literal = Result.Nodes.getNodeAs<IntegerLiteral>("immediate"); if (!Literal) { // Match calls like: const int y = 100; snprintf(x, y, ...); Literal = Result.Nodes.getNodeAs<IntegerLiteral>("constant"); } if (Type->getSize().ule(Literal->getValue())) { - Diag.Report(D->getLocStart(), ErrorID) << Name << Replacement; - Diag.Report(D->getLocStart(), NoteID) << Name; + diag(D->getLocStart(), Error, DiagnosticIDs::Error) << Name << Replacement; + diag(D->getLocStart(), Note, DiagnosticIDs::Note) << Name; } } }
--- a/build/clang-plugin/SprintfLiteralChecker.h +++ b/build/clang-plugin/SprintfLiteralChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef SprintfLiteralChecker_h__ #define SprintfLiteralChecker_h__ #include "plugin.h" -class SprintfLiteralChecker : public MatchFinder::MatchCallback { +class SprintfLiteralChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + SprintfLiteralChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
--- a/build/clang-plugin/TrivialCtorDtorChecker.cpp +++ b/build/clang-plugin/TrivialCtorDtorChecker.cpp @@ -1,29 +1,27 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "TrivialCtorDtorChecker.h" #include "CustomMatchers.h" -void TrivialCtorDtorChecker::registerMatcher(MatchFinder& AstMatcher) { - AstMatcher.addMatcher(cxxRecordDecl(hasTrivialCtorDtor()).bind("node"), - this); +void TrivialCtorDtorChecker::registerMatchers(MatchFinder* AstMatcher) { + AstMatcher->addMatcher(cxxRecordDecl(hasTrivialCtorDtor()).bind("node"), + this); } -void TrivialCtorDtorChecker::run( +void TrivialCtorDtorChecker::check( const MatchFinder::MatchResult &Result) { - DiagnosticsEngine &Diag = Result.Context->getDiagnostics(); - unsigned ErrorID = Diag.getDiagnosticIDs()->getCustomDiagID( - DiagnosticIDs::Error, - "class %0 must have trivial constructors and destructors"); + const char* Error = + "class %0 must have trivial constructors and destructors"; const CXXRecordDecl *Node = Result.Nodes.getNodeAs<CXXRecordDecl>("node"); // We need to accept non-constexpr trivial constructors as well. This occurs // when a struct contains pod members, which will not be initialized. As // constexpr values are initialized, the constructor is non-constexpr. bool BadCtor = !(Node->hasConstexprDefaultConstructor() || Node->hasTrivialDefaultConstructor()); bool BadDtor = !Node->hasTrivialDestructor(); if (BadCtor || BadDtor) - Diag.Report(Node->getLocStart(), ErrorID) << Node; + diag(Node->getLocStart(), Error, DiagnosticIDs::Error) << Node; }
--- a/build/clang-plugin/TrivialCtorDtorChecker.h +++ b/build/clang-plugin/TrivialCtorDtorChecker.h @@ -2,15 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef TrivialCtorDtorChecker_h__ #define TrivialCtorDtorChecker_h__ #include "plugin.h" -class TrivialCtorDtorChecker : public MatchFinder::MatchCallback { +class TrivialCtorDtorChecker : public BaseCheck { public: - void registerMatcher(MatchFinder& AstMatcher); - virtual void run(const MatchFinder::MatchResult &Result); + TrivialCtorDtorChecker(StringRef CheckName, + ContextType *Context = nullptr) + : BaseCheck(CheckName, Context) {} + void registerMatchers(MatchFinder* AstMatcher) override; + void check(const MatchFinder::MatchResult &Result) override; }; #endif
new file mode 100755 --- /dev/null +++ b/build/clang-plugin/import_mozilla_checks.py @@ -0,0 +1,137 @@ +#!/usr/bin/python2.7 +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import re +import sys +import glob +import shutil +import errno + + +def copy_dir_contents(src, dest): + for f in glob.glob("%s/*" % src): + try: + destname = "%s/%s" % (dest, os.path.basename(f)) + if os.path.isdir(f): + shutil.copytree(f, destname) + else: + shutil.copy2(f, destname) + except OSError as e: + if e.errno == errno.ENOTDIR: + shutil.copy2(f, destname) + elif e.errno == errno.EEXIST: + if os.path.isdir(f): + copy_dir_contents(f, destname) + else: + os.remove(destname) + shutil.copy2(f, destname) + else: + raise Exception('Directory not copied. Error: %s' % e) + +def write_cmake(module_path): + names = map(lambda f: ' ' + os.path.basename(f), + glob.glob("%s/*.cpp" % module_path)) + with open(os.path.join(module_path, 'CMakeLists.txt'), 'wb') as f: + f.write("""set(LLVM_LINK_COMPONENTS support) + +add_definitions( -DCLANG_TIDY ) +add_definitions( -DHAVE_NEW_ASTMATCHER_NAMES ) + +add_clang_library(clangTidyMozillaModule +%(names)s + + LINK_LIBS + clangAST + clangASTMatchers + clangBasic + clangLex + clangTidy + clangTidyReadabilityModule + clangTidyUtils + )""" % {'names': "\n".join(names)}) + +def add_item_to_cmake_section(cmake_path, section, library): + with open(cmake_path, 'r') as f: + lines = f.readlines() + f.close() + + libs = [] + seen_target_libs = False + for line in lines: + if line.find(section) > -1: + seen_target_libs = True + elif seen_target_libs: + if line.find(')') > -1: + break + else: + libs.append(line.strip()) + libs.append(library) + libs = sorted(libs, key = lambda s: s.lower()) + + with open(cmake_path, 'wb') as f: + seen_target_libs = False + for line in lines: + if line.find(section) > -1: + seen_target_libs = True + f.write(line) + f.writelines(map(lambda p: ' ' + p + '\n', libs)) + continue + elif seen_target_libs: + if line.find(')') > -1: + seen_target_libs = False + else: + continue + f.write(line) + + f.close() + + +def do_import(mozilla_path, clang_tidy_path): + module = 'mozilla' + module_path = os.path.join(clang_tidy_path, module) + if not os.path.isdir(module_path): + os.mkdir(module_path) + + copy_dir_contents(mozilla_path, module_path) + write_cmake(module_path) + add_item_to_cmake_section(os.path.join(module_path, '..', 'plugin', + 'CMakeLists.txt'), + 'LINK_LIBS', 'clangTidyMozillaModule') + add_item_to_cmake_section(os.path.join(module_path, '..', 'tool', + 'CMakeLists.txt'), + 'target_link_libraries', 'clangTidyMozillaModule') + with open(os.path.join(module_path, '..', 'CMakeLists.txt'), 'a') as f: + f.write('add_subdirectory(%s)\n' % module) + with open(os.path.join(module_path, '..', 'tool', 'ClangTidyMain.cpp'), 'a') as f: + f.write(''' +// This anchor is used to force the linker to link the MozillaModule. +extern volatile int MozillaModuleAnchorSource; +static int LLVM_ATTRIBUTE_UNUSED MozillaModuleAnchorDestination = + MozillaModuleAnchorSource; +''') + +def main(): + if len(sys.argv) != 3: + print """\ +Usage: import_mozilla_checks.py <mozilla-clang-plugin-path> <clang-tidy-path> +Imports the Mozilla static analysis checks into a clang-tidy source tree. +""" + + return + + mozilla_path = sys.argv[1] + if not os.path.isdir(mozilla_path): + print "Invalid path to mozilla clang plugin" + + clang_tidy_path = sys.argv[2] + if not os.path.isdir(mozilla_path): + print "Invalid path to clang-tidy source directory" + + do_import(mozilla_path, clang_tidy_path) + + +if __name__ == '__main__': + main()
--- a/build/clang-plugin/plugin.h +++ b/build/clang-plugin/plugin.h @@ -48,8 +48,19 @@ typedef ASTConsumer *ASTConsumerPtr; #define hasIgnoringParenImpCasts(x) has(x) #else // Before clang 3.9 "has" would behave like has(ignoringParenImpCasts(x)), // however doing that explicitly would not compile. #define hasIgnoringParenImpCasts(x) has(ignoringParenImpCasts(x)) #endif #endif + +// In order to support running our checks using clang-tidy, we implement a source +// compatible base check class called BaseCheck, and we use the preprocessor to +// decide which base class to pick. +#ifdef CLANG_TIDY +#include "../ClangTidy.h" +typedef clang::tidy::ClangTidyCheck BaseCheck; +typedef clang::tidy::ClangTidyContext ContextType; +#else +#include "BaseCheck.h" +#endif