Bug 1410472 - clang-plugin follows the LLVM coding style for real r=mystor

MozReview-Commit-ID: AXrQEjWzxvg
This commit is contained in:
Sylvestre Ledru
2017-10-20 19:11:50 +02:00
parent 480c1a8de7
commit 173e982fb0
67 changed files with 601 additions and 667 deletions

View File

@@ -45,14 +45,16 @@ void ArithmeticArgChecker::registerMatchers(MatchFinder* AstMatcher) {
this); this);
} }
void ArithmeticArgChecker::check( void ArithmeticArgChecker::check(const MatchFinder::MatchResult &Result) {
const MatchFinder::MatchResult &Result) { const char *Error =
const char* Error = "cannot pass an arithmetic expression of built-in types to %0"; "cannot pass an arithmetic expression of built-in types to %0";
const Expr *Expression = Result.Nodes.getNodeAs<Expr>("node"); const Expr *Expression = Result.Nodes.getNodeAs<Expr>("node");
if (const CallExpr *Call = Result.Nodes.getNodeAs<CallExpr>("call")) { if (const CallExpr *Call = Result.Nodes.getNodeAs<CallExpr>("call")) {
diag(Expression->getLocStart(), Error, DiagnosticIDs::Error) << Call->getDirectCallee(); diag(Expression->getLocStart(), Error, DiagnosticIDs::Error)
<< Call->getDirectCallee();
} else if (const CXXConstructExpr *Ctr = } else if (const CXXConstructExpr *Ctr =
Result.Nodes.getNodeAs<CXXConstructExpr>("call")) { Result.Nodes.getNodeAs<CXXConstructExpr>("call")) {
diag(Expression->getLocStart(), Error, DiagnosticIDs::Error) << Ctr->getConstructor(); diag(Expression->getLocStart(), Error, DiagnosticIDs::Error)
<< Ctr->getConstructor();
} }
} }

View File

@@ -9,8 +9,7 @@
class ArithmeticArgChecker : public BaseCheck { class ArithmeticArgChecker : public BaseCheck {
public: public:
ArithmeticArgChecker(StringRef CheckName, ArithmeticArgChecker(StringRef CheckName, ContextType *Context = nullptr)
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {} : BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override; void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override; void check(const MatchFinder::MatchResult &Result) override;

View File

@@ -7,17 +7,14 @@
void AssertAssignmentChecker::registerMatchers(MatchFinder *AstMatcher) { void AssertAssignmentChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher( AstMatcher->addMatcher(
callExpr(isAssertAssignmentTestFunc()).bind("funcCall"), callExpr(isAssertAssignmentTestFunc()).bind("funcCall"), this);
this);
} }
void AssertAssignmentChecker::check( void AssertAssignmentChecker::check(const MatchFinder::MatchResult &Result) {
const MatchFinder::MatchResult &Result) {
const CallExpr *FuncCall = Result.Nodes.getNodeAs<CallExpr>("funcCall"); const CallExpr *FuncCall = Result.Nodes.getNodeAs<CallExpr>("funcCall");
if (FuncCall && hasSideEffectAssignment(FuncCall)) { if (FuncCall && hasSideEffectAssignment(FuncCall)) {
diag(FuncCall->getLocStart(), diag(FuncCall->getLocStart(), "Forbidden assignment in assert expression",
"Forbidden assignment in assert expression",
DiagnosticIDs::Error); DiagnosticIDs::Error);
} }
} }

View File

@@ -9,8 +9,7 @@
class AssertAssignmentChecker : public BaseCheck { class AssertAssignmentChecker : public BaseCheck {
public: public:
AssertAssignmentChecker(StringRef CheckName, AssertAssignmentChecker(StringRef CheckName, ContextType *Context = nullptr)
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {} : BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override; void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override; void check(const MatchFinder::MatchResult &Result) override;

View File

@@ -19,12 +19,10 @@ void CanRunScriptChecker::registerMatchers(MatchFinder* AstMatcher) {
// and which is not a parameter of the parent function, // and which is not a parameter of the parent function,
unless(declRefExpr(to(parmVarDecl()))), unless(declRefExpr(to(parmVarDecl()))),
// and which is not a MOZ_KnownLive wrapped value. // and which is not a MOZ_KnownLive wrapped value.
unless(callExpr(callee( unless(callExpr(callee(functionDecl(hasName("MOZ_KnownLive"))))),
functionDecl(hasName("MOZ_KnownLive"))))),
expr().bind("invalidArg"))); expr().bind("invalidArg")));
auto OptionalInvalidExplicitArg = auto OptionalInvalidExplicitArg = anyOf(
anyOf(
// We want to find any argument which is invalid. // We want to find any argument which is invalid.
hasAnyArgument(InvalidArg), hasAnyArgument(InvalidArg),
@@ -46,9 +44,7 @@ void CanRunScriptChecker::registerMatchers(MatchFinder* AstMatcher) {
anyOf( anyOf(
// which derefs into an invalid arg, // which derefs into an invalid arg,
on(cxxOperatorCallExpr( on(cxxOperatorCallExpr(
anyOf( anyOf(hasAnyArgument(InvalidArg), anything()))),
hasAnyArgument(InvalidArg),
anything()))),
// or is an invalid arg. // or is an invalid arg.
on(InvalidArg), on(InvalidArg),
@@ -57,13 +53,11 @@ void CanRunScriptChecker::registerMatchers(MatchFinder* AstMatcher) {
// or a regular call expression, // or a regular call expression,
callExpr( callExpr(
// which optionally has an invalid arg. // which optionally has an invalid arg.
OptionalInvalidExplicitArg, OptionalInvalidExplicitArg, expr().bind("callExpr")),
expr().bind("callExpr")),
// or a construct expression, // or a construct expression,
cxxConstructExpr( cxxConstructExpr(
// which optionally has an invalid arg. // which optionally has an invalid arg.
OptionalInvalidExplicitArg, OptionalInvalidExplicitArg, expr().bind("constructExpr"))),
expr().bind("constructExpr"))),
anyOf( anyOf(
// We want to match the parent function. // We want to match the parent function.
@@ -135,16 +129,15 @@ void CanRunScriptChecker::buildFuncSet(ASTContext *Context) {
// a MOZ_CAN_RUN_SCRIPT annotation. // a MOZ_CAN_RUN_SCRIPT annotation.
FuncSetCallback Callback(CanRunScriptFuncs); FuncSetCallback Callback(CanRunScriptFuncs);
// We add the matcher to the finder, linking it to our callback. // We add the matcher to the finder, linking it to our callback.
Finder.addMatcher(functionDecl(hasCanRunScriptAnnotation()) Finder.addMatcher(
.bind("canRunScriptFunction"), functionDecl(hasCanRunScriptAnnotation()).bind("canRunScriptFunction"),
&Callback); &Callback);
// We start the analysis, given the ASTContext our main checker is in. // We start the analysis, given the ASTContext our main checker is in.
Finder.matchAST(*Context); Finder.matchAST(*Context);
} }
void CanRunScriptChecker::check( void CanRunScriptChecker::check(const MatchFinder::MatchResult &Result) {
const MatchFinder::MatchResult &Result) {
// If the set of functions which can run script is not yet built, then build // If the set of functions which can run script is not yet built, then build
// it. // it.
@@ -161,8 +154,7 @@ void CanRunScriptChecker::check(
const char *ErrorNonCanRunScriptParent = const char *ErrorNonCanRunScriptParent =
"functions marked as MOZ_CAN_RUN_SCRIPT can only be called from " "functions marked as MOZ_CAN_RUN_SCRIPT can only be called from "
"functions also marked as MOZ_CAN_RUN_SCRIPT"; "functions also marked as MOZ_CAN_RUN_SCRIPT";
const char* NoteNonCanRunScriptParent = const char *NoteNonCanRunScriptParent = "parent function declared here";
"parent function declared here";
const Expr *InvalidArg = Result.Nodes.getNodeAs<Expr>("invalidArg"); const Expr *InvalidArg = Result.Nodes.getNodeAs<Expr>("invalidArg");
@@ -193,7 +185,6 @@ void CanRunScriptChecker::check(
ParentFunction = nullptr; ParentFunction = nullptr;
} }
// Get the call range from either the CallExpr or the ConstructExpr. // Get the call range from either the CallExpr or the ConstructExpr.
SourceRange CallRange; SourceRange CallRange;
if (Call) { if (Call) {

View File

@@ -10,8 +10,7 @@
class CanRunScriptChecker : public BaseCheck { class CanRunScriptChecker : public BaseCheck {
public: public:
CanRunScriptChecker(StringRef CheckName, CanRunScriptChecker(StringRef CheckName, ContextType *Context = nullptr)
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {} : BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override; void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override; void check(const MatchFinder::MatchResult &Result) override;

View File

@@ -39,7 +39,7 @@ AST_MATCHER(CXXMethodDecl, isRValueRefQualified) {
return Node.getRefQualifier() == RQ_RValue; return Node.getRefQualifier() == RQ_RValue;
} }
AST_POLYMORPHIC_MATCHER(isFirstParty, \ AST_POLYMORPHIC_MATCHER(isFirstParty,
AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt)) { AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt)) {
return !inThirdPartyPath(&Node, &Finder->getASTContext()) && return !inThirdPartyPath(&Node, &Finder->getASTContext()) &&
!ASTIsInSystemHeader(Finder->getASTContext(), Node); !ASTIsInSystemHeader(Finder->getASTContext(), Node);
@@ -312,8 +312,8 @@ AST_MATCHER_P(Stmt, forFunction, internal::Matcher<FunctionDecl>,
return true; return true;
} }
} else if (const auto *LambdaExprNode = CurNode.get<LambdaExpr>()) { } else if (const auto *LambdaExprNode = CurNode.get<LambdaExpr>()) {
if(InnerMatcher.matches(*LambdaExprNode->getCallOperator(), if (InnerMatcher.matches(*LambdaExprNode->getCallOperator(), Finder,
Finder, Builder)) { Builder)) {
return true; return true;
} }
} else { } else {
@@ -325,7 +325,7 @@ AST_MATCHER_P(Stmt, forFunction, internal::Matcher<FunctionDecl>,
} }
#endif #endif
} } // namespace ast_matchers
} } // namespace clang
#endif #endif

View File

@@ -11,24 +11,19 @@ CustomTypeAnnotation GlobalClass =
CustomTypeAnnotation("moz_global_class", "global"); CustomTypeAnnotation("moz_global_class", "global");
CustomTypeAnnotation NonHeapClass = CustomTypeAnnotation NonHeapClass =
CustomTypeAnnotation("moz_nonheap_class", "non-heap"); CustomTypeAnnotation("moz_nonheap_class", "non-heap");
CustomTypeAnnotation HeapClass = CustomTypeAnnotation HeapClass = CustomTypeAnnotation("moz_heap_class", "heap");
CustomTypeAnnotation("moz_heap_class", "heap");
CustomTypeAnnotation NonTemporaryClass = CustomTypeAnnotation NonTemporaryClass =
CustomTypeAnnotation("moz_non_temporary_class", "non-temporary"); CustomTypeAnnotation("moz_non_temporary_class", "non-temporary");
void CustomTypeAnnotation::dumpAnnotationReason(BaseCheck &Check, void CustomTypeAnnotation::dumpAnnotationReason(BaseCheck &Check, QualType T,
QualType T,
SourceLocation Loc) { SourceLocation Loc) {
const char *Inherits = const char *Inherits =
"%1 is a %0 type because it inherits from a %0 type %2"; "%1 is a %0 type because it inherits from a %0 type %2";
const char* Member = const char *Member = "%1 is a %0 type because member %2 is a %0 type %3";
"%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* Array =
"%1 is a %0 type because it is an array of %0 type %2";
const char *Templ = const char *Templ =
"%1 is a %0 type because it has a template argument %0 type %2"; "%1 is a %0 type because it has a template argument %0 type %2";
const char* Implicit = const char *Implicit = "%1 is a %0 type because %2";
"%1 is a %0 type because %2";
AnnotationReason Reason = directAnnotationReason(T); AnnotationReason Reason = directAnnotationReason(T);
for (;;) { for (;;) {

View File

@@ -41,12 +41,10 @@ public:
bool hasEffectiveAnnotation(QualType T) { bool hasEffectiveAnnotation(QualType T) {
return directAnnotationReason(T).valid(); return directAnnotationReason(T).valid();
} }
void dumpAnnotationReason(BaseCheck &Check, QualType T, void dumpAnnotationReason(BaseCheck &Check, QualType T, SourceLocation Loc);
SourceLocation Loc);
void reportErrorIfPresent(BaseCheck &Check, QualType T, void reportErrorIfPresent(BaseCheck &Check, QualType T, SourceLocation Loc,
SourceLocation Loc, const char* Error, const char *Error, const char *Note) {
const char* Note) {
if (hasEffectiveAnnotation(T)) { if (hasEffectiveAnnotation(T)) {
Check.diag(Loc, Error, DiagnosticIDs::Error) << T; Check.diag(Loc, Error, DiagnosticIDs::Error) << T;
Check.diag(Loc, Note, DiagnosticIDs::Note); Check.diag(Loc, Note, DiagnosticIDs::Note);

View File

@@ -42,9 +42,8 @@ void DanglingOnTemporaryChecker::registerMatchers(MatchFinder *AstMatcher) {
// Main checker // // Main checker //
////////////////// //////////////////
auto hasParentCall = auto hasParentCall = hasParent(expr(
hasParent(expr(anyOf( anyOf(cxxOperatorCallExpr(
cxxOperatorCallExpr(
// If we're in a lamda, we may have an operator call expression // If we're in a lamda, we may have an operator call expression
// ancestor in the AST, but the temporary we're matching // ancestor in the AST, but the temporary we're matching
// against is not going to have the same lifetime as the // against is not going to have the same lifetime as the
@@ -80,9 +79,7 @@ void DanglingOnTemporaryChecker::registerMatchers(MatchFinder *AstMatcher) {
isFirstParty(), isFirstParty(),
// and which is performed on a temporary, // and which is performed on a temporary,
on(allOf( on(allOf(unless(hasType(pointerType())), isTemporary(),
unless(hasType(pointerType())),
isTemporary(),
// but which is not `this`. // but which is not `this`.
unless(cxxThisExpr()))), unless(cxxThisExpr()))),
@@ -101,9 +98,7 @@ void DanglingOnTemporaryChecker::registerMatchers(MatchFinder *AstMatcher) {
// This is the case where the call is not the direct parent, so we // This is the case where the call is not the direct parent, so we
// get its child to know in which argument tree we are. // get its child to know in which argument tree we are.
hasAncestor(expr( hasAncestor(expr(hasParentCall, expr().bind("parentCallArg"))),
hasParentCall,
expr().bind("parentCallArg"))),
// To make it optional. // To make it optional.
anything())), anything())),
this); this);
@@ -163,8 +158,7 @@ void DanglingOnTemporaryChecker::check(const MatchFinder::MatchResult &Result) {
Result.Nodes.getNodeAs<CXXConstructExpr>("parentConstructExpr"); Result.Nodes.getNodeAs<CXXConstructExpr>("parentConstructExpr");
const CXXOperatorCallExpr *ParentOperatorCallExpr = const CXXOperatorCallExpr *ParentOperatorCallExpr =
Result.Nodes.getNodeAs<CXXOperatorCallExpr>("parentOperatorCallExpr"); Result.Nodes.getNodeAs<CXXOperatorCallExpr>("parentOperatorCallExpr");
const Expr *ParentCallArg = const Expr *ParentCallArg = Result.Nodes.getNodeAs<Expr>("parentCallArg");
Result.Nodes.getNodeAs<Expr>("parentCallArg");
// Just in case. // Just in case.
if (!MemberCall) { if (!MemberCall) {
@@ -180,8 +174,8 @@ void DanglingOnTemporaryChecker::check(const MatchFinder::MatchResult &Result) {
} }
// No default constructor so we can't construct it using if/else. // No default constructor so we can't construct it using if/else.
auto FunctionEscapeData auto FunctionEscapeData =
= ParentOperatorCallExpr ParentOperatorCallExpr
? escapesFunction(ParentCallArg, ParentOperatorCallExpr) ? escapesFunction(ParentCallArg, ParentOperatorCallExpr)
: ParentCallExpr : ParentCallExpr
? escapesFunction(ParentCallArg, ParentCallExpr) ? escapesFunction(ParentCallArg, ParentCallExpr)

View File

@@ -4,13 +4,14 @@
#include "DiagnosticsMatcher.h" #include "DiagnosticsMatcher.h"
DiagnosticsMatcher::DiagnosticsMatcher(CompilerInstance& CI) : DiagnosticsMatcher::DiagnosticsMatcher(CompilerInstance &CI)
:
#define CHECK(cls, name) cls##_(name), #define CHECK(cls, name) cls##_(name),
#include "Checks.inc" #include "Checks.inc"
#undef CHECK #undef CHECK
AstMatcher() AstMatcher() {
{ #define CHECK(cls, name) \
#define CHECK(cls, name) cls ## _.registerMatchers(&AstMatcher); \ cls##_.registerMatchers(&AstMatcher); \
cls##_.registerPPCallbacks(CI); cls##_.registerPPCallbacks(CI);
#include "Checks.inc" #include "Checks.inc"
#undef CHECK #undef CHECK

View File

@@ -6,16 +6,16 @@
#include "CustomMatchers.h" #include "CustomMatchers.h"
void ExplicitImplicitChecker::registerMatchers(MatchFinder *AstMatcher) { void ExplicitImplicitChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(cxxConstructorDecl(isInterestingImplicitCtor(), AstMatcher->addMatcher(
ofClass(allOf(isConcreteClass(), cxxConstructorDecl(
decl().bind("class"))), isInterestingImplicitCtor(),
ofClass(allOf(isConcreteClass(), decl().bind("class"))),
unless(isMarkedImplicit())) unless(isMarkedImplicit()))
.bind("ctor"), .bind("ctor"),
this); this);
} }
void ExplicitImplicitChecker::check( void ExplicitImplicitChecker::check(const MatchFinder::MatchResult &Result) {
const MatchFinder::MatchResult &Result) {
// We've already checked everything in the matcher, so we just have to report // We've already checked everything in the matcher, so we just have to report
// the error. // the error.
@@ -25,7 +25,9 @@ void ExplicitImplicitChecker::check(
Result.Nodes.getNodeAs<CXXRecordDecl>("class"); Result.Nodes.getNodeAs<CXXRecordDecl>("class");
diag(Ctor->getLocation(), "bad implicit conversion constructor for %0", diag(Ctor->getLocation(), "bad implicit conversion constructor for %0",
DiagnosticIDs::Error) << Declaration->getDeclName(); DiagnosticIDs::Error)
diag(Ctor->getLocation(), "consider adding the explicit keyword to the constructor", << Declaration->getDeclName();
diag(Ctor->getLocation(),
"consider adding the explicit keyword to the constructor",
DiagnosticIDs::Note); DiagnosticIDs::Note);
} }

View File

@@ -9,8 +9,7 @@
class ExplicitImplicitChecker : public BaseCheck { class ExplicitImplicitChecker : public BaseCheck {
public: public:
ExplicitImplicitChecker(StringRef CheckName, ExplicitImplicitChecker(StringRef CheckName, ContextType *Context = nullptr)
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {} : BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override; void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override; void check(const MatchFinder::MatchResult &Result) override;

View File

@@ -26,8 +26,10 @@ void ExplicitOperatorBoolChecker::check(
!ASTIsInSystemHeader(Method->getASTContext(), *Method) && !ASTIsInSystemHeader(Method->getASTContext(), *Method) &&
isInterestingDeclForImplicitConversion(Method)) { isInterestingDeclForImplicitConversion(Method)) {
diag(Method->getLocStart(), "bad implicit conversion operator for %0", diag(Method->getLocStart(), "bad implicit conversion operator for %0",
DiagnosticIDs::Error) << Clazz; DiagnosticIDs::Error)
<< Clazz;
diag(Method->getLocStart(), "consider adding the explicit keyword to %0", diag(Method->getLocStart(), "consider adding the explicit keyword to %0",
DiagnosticIDs::Note) << "'operator bool'"; DiagnosticIDs::Note)
<< "'operator bool'";
} }
} }

View File

@@ -6,16 +6,14 @@
#include "CustomMatchers.h" #include "CustomMatchers.h"
void KungFuDeathGripChecker::registerMatchers(MatchFinder *AstMatcher) { void KungFuDeathGripChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(varDecl(hasType(isRefPtr())).bind("decl"), AstMatcher->addMatcher(varDecl(hasType(isRefPtr())).bind("decl"), this);
this);
} }
void KungFuDeathGripChecker::check( void KungFuDeathGripChecker::check(const MatchFinder::MatchResult &Result) {
const MatchFinder::MatchResult &Result) { const char *Error = "Unused \"kungFuDeathGrip\" %0 objects constructed from "
const char* Error = "%1 are prohibited";
"Unused \"kungFuDeathGrip\" %0 objects constructed from %1 are prohibited"; const char *Note = "Please switch all accesses to this %0 to go through "
const char* Note = "'%1', or explicitly pass '%1' to `mozilla::Unused`";
"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"); const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>("decl");
if (D->isReferenced() || !D->hasLocalStorage() || !D->hasInit()) { if (D->isReferenced() || !D->hasLocalStorage() || !D->hasInit()) {
@@ -74,7 +72,8 @@ void KungFuDeathGripChecker::check(
"nsCreateInstanceFromFactory", "nsCreateInstanceFromFactory",
}; };
for (uint32_t i = 0; i < sizeof(IgnoreTypes) / sizeof(IgnoreTypes[0]); ++i) { for (uint32_t i = 0; i < sizeof(IgnoreTypes) / sizeof(IgnoreTypes[0]);
++i) {
if (TD->getName() == IgnoreTypes[i]) { if (TD->getName() == IgnoreTypes[i]) {
return; return;
} }
@@ -93,6 +92,8 @@ void KungFuDeathGripChecker::check(
} }
// We cannot provide the note if we don't have an initializer // We cannot provide the note if we don't have an initializer
diag(D->getLocStart(), Error, DiagnosticIDs::Error) << D->getType() << ErrThing; diag(D->getLocStart(), Error, DiagnosticIDs::Error)
diag(E->getLocStart(), Note, DiagnosticIDs::Note) << NoteThing << getNameChecked(D); << D->getType() << ErrThing;
diag(E->getLocStart(), Note, DiagnosticIDs::Note)
<< NoteThing << getNameChecked(D);
} }

View File

@@ -9,8 +9,7 @@
class KungFuDeathGripChecker : public BaseCheck { class KungFuDeathGripChecker : public BaseCheck {
public: public:
KungFuDeathGripChecker(StringRef CheckName, KungFuDeathGripChecker(StringRef CheckName, ContextType *Context = nullptr)
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {} : BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override; void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override; void check(const MatchFinder::MatchResult &Result) override;

View File

@@ -5,8 +5,8 @@
#ifndef MemMoveAnnotation_h__ #ifndef MemMoveAnnotation_h__
#define MemMoveAnnotation_h__ #define MemMoveAnnotation_h__
#include "CustomTypeAnnotation.h"
#include "CustomMatchers.h" #include "CustomMatchers.h"
#include "CustomTypeAnnotation.h"
#include "Utils.h" #include "Utils.h"
class MemMoveAnnotation final : public CustomTypeAnnotation { class MemMoveAnnotation final : public CustomTypeAnnotation {
@@ -24,30 +24,19 @@ protected:
// This doesn't check that it's really ::std::pair and not // This doesn't check that it's really ::std::pair and not
// ::std::something_else::pair, but should be good enough. // ::std::something_else::pair, but should be good enough.
StringRef Name = getNameChecked(D); StringRef Name = getNameChecked(D);
if (Name == "pair" || if (Name == "pair" || Name == "atomic" ||
Name == "atomic" ||
// libstdc++ specific names // libstdc++ specific names
Name == "__atomic_base" || Name == "__atomic_base" || Name == "atomic_bool" ||
Name == "atomic_bool" ||
// MSVCRT specific names // MSVCRT specific names
Name == "_Atomic_impl" || Name == "_Atomic_impl" || Name == "_Atomic_base" ||
Name == "_Atomic_base" || Name == "_Atomic_bool" || Name == "_Atomic_char" ||
Name == "_Atomic_bool" || Name == "_Atomic_schar" || Name == "_Atomic_uchar" ||
Name == "_Atomic_char" || Name == "_Atomic_char16_t" || Name == "_Atomic_char32_t" ||
Name == "_Atomic_schar" || Name == "_Atomic_wchar_t" || Name == "_Atomic_short" ||
Name == "_Atomic_uchar" || Name == "_Atomic_ushort" || Name == "_Atomic_int" ||
Name == "_Atomic_char16_t" || Name == "_Atomic_uint" || Name == "_Atomic_long" ||
Name == "_Atomic_char32_t" || Name == "_Atomic_ulong" || Name == "_Atomic_llong" ||
Name == "_Atomic_wchar_t" || Name == "_Atomic_ullong" || Name == "_Atomic_address") {
Name == "_Atomic_short" ||
Name == "_Atomic_ushort" ||
Name == "_Atomic_int" ||
Name == "_Atomic_uint" ||
Name == "_Atomic_long" ||
Name == "_Atomic_ulong" ||
Name == "_Atomic_llong" ||
Name == "_Atomic_ullong" ||
Name == "_Atomic_address") {
return ""; return "";
} }
return "it is an stl-provided type not guaranteed to be memmove-able"; return "it is an stl-provided type not guaranteed to be memmove-able";

View File

@@ -2,8 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "plugin.h"
#include "DiagnosticsMatcher.h" #include "DiagnosticsMatcher.h"
#include "plugin.h"
#include "clang/Frontend/FrontendPluginRegistry.h" #include "clang/Frontend/FrontendPluginRegistry.h"
class MozCheckAction : public PluginASTAction { class MozCheckAction : public PluginASTAction {

View File

@@ -24,8 +24,8 @@ public:
}; };
// Register the MozillaTidyModule using this statically initialized variable. // Register the MozillaTidyModule using this statically initialized variable.
static ClangTidyModuleRegistry::Add<MozillaModule> X("mozilla-module", static ClangTidyModuleRegistry::Add<MozillaModule>
"Adds Mozilla lint checks."); X("mozilla-module", "Adds Mozilla lint checks.");
} // namespace tidy } // namespace tidy
} // namespace clang } // namespace clang

View File

@@ -13,8 +13,7 @@ void MustOverrideChecker::registerPPCallbacks(CompilerInstance& CI) {
this->CI = &CI; this->CI = &CI;
} }
void MustOverrideChecker::check( void MustOverrideChecker::check(const MatchFinder::MatchResult &Result) {
const MatchFinder::MatchResult &Result) {
auto D = Result.Nodes.getNodeAs<CXXRecordDecl>("class"); auto D = Result.Nodes.getNodeAs<CXXRecordDecl>("class");
// Look through all of our immediate bases to find methods that need to be // Look through all of our immediate bases to find methods that need to be
@@ -52,9 +51,8 @@ void MustOverrideChecker::check(
} }
} }
if (!Overridden) { if (!Overridden) {
diag(D->getLocation(), "%0 must override %1", diag(D->getLocation(), "%0 must override %1", DiagnosticIDs::Error)
DiagnosticIDs::Error) << D->getDeclName() << D->getDeclName() << O->getDeclName();
<< O->getDeclName();
diag(O->getLocation(), "function to override is here", diag(O->getLocation(), "function to override is here",
DiagnosticIDs::Note); DiagnosticIDs::Note);
} }

View File

@@ -9,8 +9,7 @@
class MustOverrideChecker : public BaseCheck { class MustOverrideChecker : public BaseCheck {
public: public:
MustOverrideChecker(StringRef CheckName, MustOverrideChecker(StringRef CheckName, ContextType *Context = nullptr)
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context), CI(nullptr) {} : BaseCheck(CheckName, Context), CI(nullptr) {}
void registerMatchers(MatchFinder *AstMatcher) override; void registerMatchers(MatchFinder *AstMatcher) override;
void registerPPCallbacks(CompilerInstance &CI) override; void registerPPCallbacks(CompilerInstance &CI) override;

View File

@@ -7,9 +7,11 @@
void MustReturnFromCallerChecker::registerMatchers(MatchFinder *AstMatcher) { void MustReturnFromCallerChecker::registerMatchers(MatchFinder *AstMatcher) {
// Look for a call to a MOZ_MUST_RETURN_FROM_CALLER function // Look for a call to a MOZ_MUST_RETURN_FROM_CALLER function
AstMatcher->addMatcher(callExpr(callee(functionDecl(isMozMustReturnFromCaller())), AstMatcher->addMatcher(
callExpr(callee(functionDecl(isMozMustReturnFromCaller())),
anyOf(hasAncestor(lambdaExpr().bind("containing-lambda")), anyOf(hasAncestor(lambdaExpr().bind("containing-lambda")),
hasAncestor(functionDecl().bind("containing-func")))).bind("call"), hasAncestor(functionDecl().bind("containing-func"))))
.bind("call"),
this); this);
} }
@@ -52,9 +54,8 @@ void MustReturnFromCallerChecker::check(
} }
} }
bool bool MustReturnFromCallerChecker::immediatelyReturns(
MustReturnFromCallerChecker::immediatelyReturns(RecurseGuard<const CFGBlock *> Block, RecurseGuard<const CFGBlock *> Block, ASTContext *TheContext,
ASTContext *TheContext,
size_t FromIdx) { size_t FromIdx) {
if (Block.isRepeat()) { if (Block.isRepeat()) {
return false; return false;
@@ -73,8 +74,7 @@ MustReturnFromCallerChecker::immediatelyReturns(RecurseGuard<const CFGBlock *> B
// It is also, of course, OK to look at a ReturnStmt. // It is also, of course, OK to look at a ReturnStmt.
if (isa<ReturnStmt>(AfterTrivials) || if (isa<ReturnStmt>(AfterTrivials) ||
isa<CXXConstructExpr>(AfterTrivials) || isa<CXXConstructExpr>(AfterTrivials) ||
isa<DeclRefExpr>(AfterTrivials) || isa<DeclRefExpr>(AfterTrivials) || isa<MemberExpr>(AfterTrivials)) {
isa<MemberExpr>(AfterTrivials)) {
continue; continue;
} }
@@ -83,7 +83,8 @@ MustReturnFromCallerChecker::immediatelyReturns(RecurseGuard<const CFGBlock *> B
// to be MOZ_MAY_CALL_AFTER_MUST_RETURN (like operator T*()). // to be MOZ_MAY_CALL_AFTER_MUST_RETURN (like operator T*()).
if (auto CE = dyn_cast<CallExpr>(AfterTrivials)) { if (auto CE = dyn_cast<CallExpr>(AfterTrivials)) {
auto Callee = CE->getDirectCallee(); auto Callee = CE->getDirectCallee();
if (Callee && hasCustomAnnotation(Callee, "moz_may_call_after_must_return")) { if (Callee &&
hasCustomAnnotation(Callee, "moz_may_call_after_must_return")) {
continue; continue;
} }

View File

@@ -5,10 +5,10 @@
#ifndef MustReturnFromCallerChecker_h__ #ifndef MustReturnFromCallerChecker_h__
#define MustReturnFromCallerChecker_h__ #define MustReturnFromCallerChecker_h__
#include "plugin.h"
#include "Utils.h"
#include "RecurseGuard.h" #include "RecurseGuard.h"
#include "StmtToBlockMap.h" #include "StmtToBlockMap.h"
#include "Utils.h"
#include "plugin.h"
class MustReturnFromCallerChecker : public BaseCheck { class MustReturnFromCallerChecker : public BaseCheck {
public: public:
@@ -17,10 +17,10 @@ public:
: BaseCheck(CheckName, Context) {} : BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override; void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override; void check(const MatchFinder::MatchResult &Result) override;
private: private:
bool immediatelyReturns(RecurseGuard<const CFGBlock *> Block, bool immediatelyReturns(RecurseGuard<const CFGBlock *> Block,
ASTContext *TheContext, ASTContext *TheContext, size_t FromIdx);
size_t FromIdx);
}; };
#endif #endif

View File

@@ -16,11 +16,11 @@ void MustUseChecker::registerMatchers(MatchFinder* AstMatcher) {
AstMatcher->addMatcher(whileStmt().bind("while"), this); AstMatcher->addMatcher(whileStmt().bind("while"), this);
AstMatcher->addMatcher(doStmt().bind("do"), this); AstMatcher->addMatcher(doStmt().bind("do"), this);
AstMatcher->addMatcher(forStmt().bind("for"), this); AstMatcher->addMatcher(forStmt().bind("for"), this);
AstMatcher->addMatcher(binaryOperator(binaryCommaOperator()).bind("bin"), this); AstMatcher->addMatcher(binaryOperator(binaryCommaOperator()).bind("bin"),
this);
} }
void MustUseChecker::check( void MustUseChecker::check(const MatchFinder::MatchResult &Result) {
const MatchFinder::MatchResult &Result) {
if (auto SC = Result.Nodes.getNodeAs<SwitchCase>("switchcase")) { if (auto SC = Result.Nodes.getNodeAs<SwitchCase>("switchcase")) {
handleUnusedExprResult(SC->getSubStmt()); handleUnusedExprResult(SC->getSubStmt());
} }
@@ -56,7 +56,8 @@ void MustUseChecker::handleUnusedExprResult(const Stmt *Statement) {
QualType T = E->getType(); QualType T = E->getType();
if (MustUse.hasEffectiveAnnotation(T) && !isIgnoredExprForMustUse(E)) { if (MustUse.hasEffectiveAnnotation(T) && !isIgnoredExprForMustUse(E)) {
diag(E->getLocStart(), "Unused value of must-use type %0", diag(E->getLocStart(), "Unused value of must-use type %0",
DiagnosticIDs::Error) << T; DiagnosticIDs::Error)
<< T;
MustUse.dumpAnnotationReason(*this, T, E->getLocStart()); MustUse.dumpAnnotationReason(*this, T, E->getLocStart());
} }
} }

View File

@@ -9,8 +9,7 @@
class MustUseChecker : public BaseCheck { class MustUseChecker : public BaseCheck {
public: public:
MustUseChecker(StringRef CheckName, MustUseChecker(StringRef CheckName, ContextType *Context = nullptr)
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {} : BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override; void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override; void check(const MatchFinder::MatchResult &Result) override;

View File

@@ -18,22 +18,21 @@ void NaNExprChecker::registerMatchers(MatchFinder* AstMatcher) {
this); this);
} }
void NaNExprChecker::check( void NaNExprChecker::check(const MatchFinder::MatchResult &Result) {
const MatchFinder::MatchResult &Result) {
if (!Result.Context->getLangOpts().CPlusPlus) { if (!Result.Context->getLangOpts().CPlusPlus) {
// mozilla::IsNaN is not usable in C, so there is no point in issuing these // mozilla::IsNaN is not usable in C, so there is no point in issuing these
// warnings. // warnings.
return; return;
} }
const BinaryOperator *Expression = Result.Nodes.getNodeAs<BinaryOperator>( const BinaryOperator *Expression =
"node"); Result.Nodes.getNodeAs<BinaryOperator>("node");
const DeclRefExpr *LHS = Result.Nodes.getNodeAs<DeclRefExpr>("lhs"); const DeclRefExpr *LHS = Result.Nodes.getNodeAs<DeclRefExpr>("lhs");
const DeclRefExpr *RHS = Result.Nodes.getNodeAs<DeclRefExpr>("rhs"); const DeclRefExpr *RHS = Result.Nodes.getNodeAs<DeclRefExpr>("rhs");
const ImplicitCastExpr *LHSExpr = dyn_cast<ImplicitCastExpr>( const ImplicitCastExpr *LHSExpr =
Expression->getLHS()); dyn_cast<ImplicitCastExpr>(Expression->getLHS());
const ImplicitCastExpr *RHSExpr = dyn_cast<ImplicitCastExpr>( const ImplicitCastExpr *RHSExpr =
Expression->getRHS()); dyn_cast<ImplicitCastExpr>(Expression->getRHS());
// The AST subtree that we are looking for will look like this: // The AST subtree that we are looking for will look like this:
// -BinaryOperator ==/!= // -BinaryOperator ==/!=
// |-ImplicitCastExpr LValueToRValue // |-ImplicitCastExpr LValueToRValue
@@ -47,7 +46,8 @@ void NaNExprChecker::check(
std::distance(LHSExpr->child_begin(), LHSExpr->child_end()) == 1 && std::distance(LHSExpr->child_begin(), LHSExpr->child_end()) == 1 &&
std::distance(RHSExpr->child_begin(), RHSExpr->child_end()) == 1 && std::distance(RHSExpr->child_begin(), RHSExpr->child_end()) == 1 &&
*LHSExpr->child_begin() == LHS && *RHSExpr->child_begin() == RHS) { *LHSExpr->child_begin() == LHS && *RHSExpr->child_begin() == RHS) {
diag(Expression->getLocStart(), "comparing a floating point value to itself for " diag(Expression->getLocStart(),
"comparing a floating point value to itself for "
"NaN checking can lead to incorrect results", "NaN checking can lead to incorrect results",
DiagnosticIDs::Error); DiagnosticIDs::Error);
diag(Expression->getLocStart(), "consider using mozilla::IsNaN instead", diag(Expression->getLocStart(), "consider using mozilla::IsNaN instead",

View File

@@ -9,8 +9,7 @@
class NaNExprChecker : public BaseCheck { class NaNExprChecker : public BaseCheck {
public: public:
NaNExprChecker(StringRef CheckName, NaNExprChecker(StringRef CheckName, ContextType *Context = nullptr)
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {} : BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override; void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override; void check(const MatchFinder::MatchResult &Result) override;

View File

@@ -14,8 +14,7 @@ void NeedsNoVTableTypeChecker::registerMatchers(MatchFinder* AstMatcher) {
this); this);
} }
void NeedsNoVTableTypeChecker::check( void NeedsNoVTableTypeChecker::check(const MatchFinder::MatchResult &Result) {
const MatchFinder::MatchResult &Result) {
const ClassTemplateSpecializationDecl *Specialization = const ClassTemplateSpecializationDecl *Specialization =
Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("node"); Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("node");
@@ -32,9 +31,9 @@ void NeedsNoVTableTypeChecker::check(
diag(Specialization->getLocStart(), diag(Specialization->getLocStart(),
"%0 cannot be instantiated because %1 has a VTable", "%0 cannot be instantiated because %1 has a VTable",
DiagnosticIDs::Error) << Specialization DiagnosticIDs::Error)
<< Offender; << Specialization << Offender;
diag(Specialization->getPointOfInstantiation(), diag(Specialization->getPointOfInstantiation(),
"bad instantiation of %0 requested here", "bad instantiation of %0 requested here", DiagnosticIDs::Note)
DiagnosticIDs::Note) << Specialization; << Specialization;
} }

View File

@@ -9,8 +9,7 @@
class NeedsNoVTableTypeChecker : public BaseCheck { class NeedsNoVTableTypeChecker : public BaseCheck {
public: public:
NeedsNoVTableTypeChecker(StringRef CheckName, NeedsNoVTableTypeChecker(StringRef CheckName, ContextType *Context = nullptr)
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {} : BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override; void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override; void check(const MatchFinder::MatchResult &Result) override;

View File

@@ -7,7 +7,8 @@
void NoAddRefReleaseOnReturnChecker::registerMatchers(MatchFinder *AstMatcher) { void NoAddRefReleaseOnReturnChecker::registerMatchers(MatchFinder *AstMatcher) {
// Look for all of the calls to AddRef() or Release() // Look for all of the calls to AddRef() or Release()
AstMatcher->addMatcher(memberExpr(isAddRefOrRelease(), hasParent(callExpr())).bind("member"), AstMatcher->addMatcher(
memberExpr(isAddRefOrRelease(), hasParent(callExpr())).bind("member"),
this); this);
} }
@@ -24,8 +25,7 @@ void NoAddRefReleaseOnReturnChecker::check(
diag(Call->getLocStart(), diag(Call->getLocStart(),
"%1 cannot be called on the return value of %0", "%1 cannot be called on the return value of %0",
DiagnosticIDs::Error) DiagnosticIDs::Error)
<< Callee << Callee << dyn_cast<CXXMethodDecl>(Member->getMemberDecl());
<< dyn_cast<CXXMethodDecl>(Member->getMemberDecl());
} }
} }
} }

View File

@@ -10,14 +10,12 @@ void NoAutoTypeChecker::registerMatchers(MatchFinder* AstMatcher) {
this); this);
} }
void NoAutoTypeChecker::check( void NoAutoTypeChecker::check(const MatchFinder::MatchResult &Result) {
const MatchFinder::MatchResult &Result) {
const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>("node"); const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>("node");
diag(D->getLocation(), diag(D->getLocation(), "Cannot use auto to declare a variable of type %0",
"Cannot use auto to declare a variable of type %0", DiagnosticIDs::Error)
DiagnosticIDs::Error) << D->getType(); << D->getType();
diag(D->getLocation(), diag(D->getLocation(), "Please write out this type explicitly",
"Please write out this type explicitly",
DiagnosticIDs::Note); DiagnosticIDs::Note);
} }

View File

@@ -9,8 +9,7 @@
class NoAutoTypeChecker : public BaseCheck { class NoAutoTypeChecker : public BaseCheck {
public: public:
NoAutoTypeChecker(StringRef CheckName, NoAutoTypeChecker(StringRef CheckName, ContextType *Context = nullptr)
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {} : BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override; void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override; void check(const MatchFinder::MatchResult &Result) override;

View File

@@ -34,10 +34,8 @@ void NoDuplicateRefCntMemberChecker::check(
if (BaseRefCntMember) { if (BaseRefCntMember) {
if (RefCntMember) { if (RefCntMember) {
// We have an mRefCnt, and superclass has an mRefCnt // We have an mRefCnt, and superclass has an mRefCnt
const char* Error = const char *Error = "Refcounted record %0 has multiple mRefCnt members";
"Refcounted record %0 has multiple mRefCnt members"; const char *Note1 = "Superclass %0 also has an mRefCnt member";
const char* Note1 =
"Superclass %0 also has an mRefCnt member";
const char *Note2 = const char *Note2 =
"Consider using the _INHERITED macros for AddRef and Release here"; "Consider using the _INHERITED macros for AddRef and Release here";
@@ -48,10 +46,9 @@ void NoDuplicateRefCntMemberChecker::check(
} }
if (FoundRefCntBase) { if (FoundRefCntBase) {
const char* Error = const char *Error = "Refcounted record %0 has multiple superclasses "
"Refcounted record %0 has multiple superclasses with mRefCnt members"; "with mRefCnt members";
const char* Note = const char *Note = "Superclass %0 has an mRefCnt member";
"Superclass %0 has an mRefCnt member";
// superclass has mRefCnt, and another superclass also has an mRefCnt // superclass has mRefCnt, and another superclass also has an mRefCnt
diag(D->getLocStart(), Error, DiagnosticIDs::Error) << D; diag(D->getLocStart(), Error, DiagnosticIDs::Error) << D;

View File

@@ -5,10 +5,10 @@
#include "NoExplicitMoveConstructorChecker.h" #include "NoExplicitMoveConstructorChecker.h"
#include "CustomMatchers.h" #include "CustomMatchers.h"
void NoExplicitMoveConstructorChecker::registerMatchers(MatchFinder* AstMatcher) { void NoExplicitMoveConstructorChecker::registerMatchers(
MatchFinder *AstMatcher) {
AstMatcher->addMatcher( AstMatcher->addMatcher(
cxxConstructorDecl(isExplicitMoveConstructor()).bind("node"), cxxConstructorDecl(isExplicitMoveConstructor()).bind("node"), this);
this);
} }
void NoExplicitMoveConstructorChecker::check( void NoExplicitMoveConstructorChecker::check(

View File

@@ -9,14 +9,11 @@ MemMoveAnnotation NonMemMovable = MemMoveAnnotation();
void NonMemMovableMemberChecker::registerMatchers(MatchFinder *AstMatcher) { void NonMemMovableMemberChecker::registerMatchers(MatchFinder *AstMatcher) {
// Handle non-mem-movable members // Handle non-mem-movable members
AstMatcher->addMatcher( AstMatcher->addMatcher(cxxRecordDecl(needsMemMovableMembers()).bind("decl"),
cxxRecordDecl(needsMemMovableMembers())
.bind("decl"),
this); this);
} }
void NonMemMovableMemberChecker::check( void NonMemMovableMemberChecker::check(const MatchFinder::MatchResult &Result) {
const MatchFinder::MatchResult &Result) {
const char *Error = const char *Error =
"class %0 cannot have non-memmovable member %1 of type %2"; "class %0 cannot have non-memmovable member %1 of type %2";
@@ -29,10 +26,9 @@ void NonMemMovableMemberChecker::check(
QualType Type = Field->getType(); QualType Type = Field->getType();
if (NonMemMovable.hasEffectiveAnnotation(Type)) { if (NonMemMovable.hasEffectiveAnnotation(Type)) {
diag(Field->getLocation(), Error, DiagnosticIDs::Error) diag(Field->getLocation(), Error, DiagnosticIDs::Error)
<< Declaration << Declaration << Field << Type;
<< Field NonMemMovable.dumpAnnotationReason(*this, Type,
<< Type; Declaration->getLocation());
NonMemMovable.dumpAnnotationReason(*this, Type, Declaration->getLocation());
} }
} }
} }

View File

@@ -5,7 +5,8 @@
#include "NonMemMovableTemplateArgChecker.h" #include "NonMemMovableTemplateArgChecker.h"
#include "CustomMatchers.h" #include "CustomMatchers.h"
void NonMemMovableTemplateArgChecker::registerMatchers(MatchFinder* AstMatcher) { void NonMemMovableTemplateArgChecker::registerMatchers(
MatchFinder *AstMatcher) {
// Handle non-mem-movable template specializations // Handle non-mem-movable template specializations
AstMatcher->addMatcher( AstMatcher->addMatcher(
classTemplateSpecializationDecl( classTemplateSpecializationDecl(
@@ -19,8 +20,7 @@ void NonMemMovableTemplateArgChecker::check(
const MatchFinder::MatchResult &Result) { const MatchFinder::MatchResult &Result) {
const char *Error = const char *Error =
"Cannot instantiate %0 with non-memmovable template argument %1"; "Cannot instantiate %0 with non-memmovable template argument %1";
const char* Note = const char *Note = "instantiation of %0 requested here";
"instantiation of %0 requested here";
// Get the specialization // Get the specialization
const ClassTemplateSpecializationDecl *Specialization = const ClassTemplateSpecializationDecl *Specialization =
@@ -33,9 +33,8 @@ void NonMemMovableTemplateArgChecker::check(
for (unsigned i = 0; i < Args.size(); ++i) { for (unsigned i = 0; i < Args.size(); ++i) {
QualType ArgType = Args[i].getAsType(); QualType ArgType = Args[i].getAsType();
if (NonMemMovable.hasEffectiveAnnotation(ArgType)) { if (NonMemMovable.hasEffectiveAnnotation(ArgType)) {
diag(Specialization->getLocation(), Error, diag(Specialization->getLocation(), Error, DiagnosticIDs::Error)
DiagnosticIDs::Error) << Specialization << Specialization << ArgType;
<< ArgType;
// XXX It would be really nice if we could get the instantiation stack // XXX It would be really nice if we could get the instantiation stack
// information // information
// from Sema such that we could print a full template instantiation stack, // from Sema such that we could print a full template instantiation stack,

View File

@@ -5,8 +5,7 @@
#include "NonParamInsideFunctionDeclChecker.h" #include "NonParamInsideFunctionDeclChecker.h"
#include "CustomMatchers.h" #include "CustomMatchers.h"
class NonParamAnnotation : public CustomTypeAnnotation class NonParamAnnotation : public CustomTypeAnnotation {
{
public: public:
NonParamAnnotation() : CustomTypeAnnotation("moz_non_param", "non-param"){}; NonParamAnnotation() : CustomTypeAnnotation("moz_non_param", "non-param"){};
@@ -28,7 +27,9 @@ protected:
for (auto F : RD->fields()) { for (auto F : RD->fields()) {
for (auto A : F->attrs()) { for (auto A : F->attrs()) {
if (isa<AlignedAttr>(A)) { if (isa<AlignedAttr>(A)) {
return ("member '" + F->getName() + "' has an alignas(_) annotation").str(); return ("member '" + F->getName() +
"' has an alignas(_) annotation")
.str();
} }
} }
} }
@@ -41,17 +42,17 @@ protected:
}; };
NonParamAnnotation NonParam; NonParamAnnotation NonParam;
void NonParamInsideFunctionDeclChecker::registerMatchers(MatchFinder* AstMatcher) { void NonParamInsideFunctionDeclChecker::registerMatchers(
MatchFinder *AstMatcher) {
AstMatcher->addMatcher( AstMatcher->addMatcher(
functionDecl(anyOf(allOf(isDefinition(), functionDecl(
hasAncestor(classTemplateSpecializationDecl() anyOf(allOf(isDefinition(),
.bind("spec"))), hasAncestor(
classTemplateSpecializationDecl().bind("spec"))),
isDefinition())) isDefinition()))
.bind("func"), .bind("func"),
this); this);
AstMatcher->addMatcher( AstMatcher->addMatcher(lambdaExpr().bind("lambda"), this);
lambdaExpr().bind("lambda"),
this);
} }
void NonParamInsideFunctionDeclChecker::check( void NonParamInsideFunctionDeclChecker::check(
@@ -98,14 +99,15 @@ void NonParamInsideFunctionDeclChecker::check(
QualType T = p->getType().withoutLocalFastQualifiers(); QualType T = p->getType().withoutLocalFastQualifiers();
if (NonParam.hasEffectiveAnnotation(T)) { if (NonParam.hasEffectiveAnnotation(T)) {
diag(p->getLocation(), "Type %0 must not be used as parameter", diag(p->getLocation(), "Type %0 must not be used as parameter",
DiagnosticIDs::Error) << T; DiagnosticIDs::Error)
diag(p->getLocation(), "Please consider passing a const reference instead", << T;
diag(p->getLocation(),
"Please consider passing a const reference instead",
DiagnosticIDs::Note); DiagnosticIDs::Note);
if (Spec) { if (Spec) {
diag(Spec->getPointOfInstantiation(), diag(Spec->getPointOfInstantiation(),
"The bad argument was passed to %0 here", "The bad argument was passed to %0 here", DiagnosticIDs::Note)
DiagnosticIDs::Note)
<< Spec->getSpecializedTemplate(); << Spec->getSpecializedTemplate();
} }

View File

@@ -6,8 +6,7 @@
#include "CustomMatchers.h" #include "CustomMatchers.h"
void OverrideBaseCallChecker::registerMatchers(MatchFinder *AstMatcher) { void OverrideBaseCallChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher(cxxRecordDecl(hasBaseClasses()).bind("class"), AstMatcher->addMatcher(cxxRecordDecl(hasBaseClasses()).bind("class"), this);
this);
} }
bool OverrideBaseCallChecker::isRequiredBaseMethod( bool OverrideBaseCallChecker::isRequiredBaseMethod(
@@ -23,8 +22,8 @@ void OverrideBaseCallChecker::evaluateExpression(
} }
if (auto MemberFuncCall = dyn_cast<CXXMemberCallExpr>(StmtExpr)) { if (auto MemberFuncCall = dyn_cast<CXXMemberCallExpr>(StmtExpr)) {
if (auto Method = dyn_cast<CXXMethodDecl>( if (auto Method =
MemberFuncCall->getDirectCallee())) { dyn_cast<CXXMethodDecl>(MemberFuncCall->getDirectCallee())) {
findBaseMethodCall(Method, MethodList); findBaseMethodCall(Method, MethodList);
} }
} }
@@ -63,8 +62,7 @@ void OverrideBaseCallChecker::findBaseMethodCall(
} }
} }
void OverrideBaseCallChecker::check( void OverrideBaseCallChecker::check(const MatchFinder::MatchResult &Result) {
const MatchFinder::MatchResult &Result) {
const char *Error = const char *Error =
"Method %0 must be called in all overrides, but is not called in " "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";
@@ -105,8 +103,7 @@ void OverrideBaseCallChecker::check(
BaseMethod->printQualifiedName(OS); BaseMethod->printQualifiedName(OS);
diag(Method->getLocation(), Error, DiagnosticIDs::Error) diag(Method->getLocation(), Error, DiagnosticIDs::Error)
<< OS.str() << OS.str() << Decl->getName();
<< Decl->getName();
} }
} }
} }

View File

@@ -9,11 +9,11 @@
class OverrideBaseCallChecker : public BaseCheck { class OverrideBaseCallChecker : public BaseCheck {
public: public:
OverrideBaseCallChecker(StringRef CheckName, OverrideBaseCallChecker(StringRef CheckName, ContextType *Context = nullptr)
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {} : BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override; void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override; void check(const MatchFinder::MatchResult &Result) override;
private: private:
void evaluateExpression(const Stmt *StmtExpr, void evaluateExpression(const Stmt *StmtExpr,
std::list<const CXXMethodDecl *> &MethodList); std::list<const CXXMethodDecl *> &MethodList);

View File

@@ -17,8 +17,7 @@
// The RecurseGuard object will unregister its object when it is destroyed, and // The RecurseGuard object will unregister its object when it is destroyed, and
// has a method `isRepeat()` which will return `true` if the item was already // has a method `isRepeat()` which will return `true` if the item was already
// seen. // seen.
template<typename T> template <typename T> class RecurseGuard {
class RecurseGuard {
public: public:
RecurseGuard(T Thing) : Thing(Thing), Set(new DenseSet<T>()), Repeat(false) { RecurseGuard(T Thing) : Thing(Thing), Set(new DenseSet<T>()), Repeat(false) {
Set->insert(Thing); Set->insert(Thing);
@@ -42,17 +41,11 @@ public:
T get() { return Thing; } T get() { return Thing; }
operator T() { operator T() { return Thing; }
return Thing;
}
T operator ->() { T operator->() { return Thing; }
return Thing;
}
RecurseGuard recurse(T NewThing) { RecurseGuard recurse(T NewThing) { return RecurseGuard(NewThing, Set); }
return RecurseGuard(NewThing, Set);
}
private: private:
T Thing; T Thing;

View File

@@ -5,7 +5,8 @@
#include "RefCountedCopyConstructorChecker.h" #include "RefCountedCopyConstructorChecker.h"
#include "CustomMatchers.h" #include "CustomMatchers.h"
void RefCountedCopyConstructorChecker::registerMatchers(MatchFinder* AstMatcher) { void RefCountedCopyConstructorChecker::registerMatchers(
MatchFinder *AstMatcher) {
AstMatcher->addMatcher( AstMatcher->addMatcher(
cxxConstructExpr( cxxConstructExpr(
hasDeclaration(cxxConstructorDecl(isCompilerProvidedCopyConstructor(), hasDeclaration(cxxConstructorDecl(isCompilerProvidedCopyConstructor(),
@@ -18,8 +19,7 @@ void RefCountedCopyConstructorChecker::check(
const MatchFinder::MatchResult &Result) { const MatchFinder::MatchResult &Result) {
const char *Error = const char *Error =
"Invalid use of compiler-provided copy constructor on refcounted type"; "Invalid use of compiler-provided copy constructor on refcounted type";
const char* Note = const char *Note = "The default copy constructor also copies the "
"The default copy constructor also copies the "
"default mRefCnt property, leading to reference " "default mRefCnt property, leading to reference "
"count imbalance issues. Please provide your own " "count imbalance issues. Please provide your own "
"copy constructor which only copies the fields which " "copy constructor which only copies the fields which "

View File

@@ -15,26 +15,25 @@ void RefCountedInsideLambdaChecker::registerMatchers(MatchFinder* AstMatcher) {
// in a return value (either from lambdas, or in c++14, auto functions). // 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. // We check these lambdas' capture lists for raw pointers to refcounted types.
AstMatcher->addMatcher( AstMatcher->addMatcher(functionDecl(returns(recordType(hasDeclaration(
functionDecl(returns(recordType(hasDeclaration(cxxRecordDecl( cxxRecordDecl(isLambdaDecl()).bind("decl"))))),
isLambdaDecl()).bind("decl"))))),
this);
AstMatcher->addMatcher(lambdaExpr().bind("lambdaExpr"),
this); this);
AstMatcher->addMatcher(lambdaExpr().bind("lambdaExpr"), this);
AstMatcher->addMatcher( AstMatcher->addMatcher(
classTemplateSpecializationDecl(hasAnyTemplateArgument(refersToType( classTemplateSpecializationDecl(
recordType(hasDeclaration(cxxRecordDecl( hasAnyTemplateArgument(refersToType(recordType(
isLambdaDecl()).bind("decl")))))), hasDeclaration(cxxRecordDecl(isLambdaDecl()).bind("decl")))))),
this); this);
} }
void RefCountedInsideLambdaChecker::emitDiagnostics(SourceLocation Loc, void RefCountedInsideLambdaChecker::emitDiagnostics(SourceLocation Loc,
StringRef Name, StringRef Name,
QualType Type) { QualType Type) {
diag(Loc, "Refcounted variable '%0' of type %1 cannot be captured by a lambda", diag(Loc,
DiagnosticIDs::Error) << Name << Type; "Refcounted variable '%0' of type %1 cannot be captured by a lambda",
diag(Loc, "Please consider using a smart pointer", DiagnosticIDs::Error)
DiagnosticIDs::Note); << Name << Type;
diag(Loc, "Please consider using a smart pointer", DiagnosticIDs::Note);
} }
void RefCountedInsideLambdaChecker::check( void RefCountedInsideLambdaChecker::check(
@@ -66,17 +65,18 @@ void RefCountedInsideLambdaChecker::check(
for (const LambdaCapture &Capture : Lambda->captures()) { for (const LambdaCapture &Capture : Lambda->captures()) {
// Check if any of the captures are ByRef. If they are, we have nothing to // Check if any of the captures are ByRef. If they are, we have nothing to
// report, as it's OK to capture raw pointers to refcounted objects so long as // report, as it's OK to capture raw pointers to refcounted objects so long
// the Lambda doesn't escape the current scope, which is required by ByRef // as the Lambda doesn't escape the current scope, which is required by
// captures already. // ByRef captures already.
if (Capture.getCaptureKind() == LCK_ByRef) { if (Capture.getCaptureKind() == LCK_ByRef) {
return; return;
} }
// Check if this capture is byvalue, and captures a strong reference to this. // Check if this capture is byvalue, and captures a strong reference to
// XXX: Do we want to make sure that this type which we are capturing is a "Smart Pointer" somehow? // this.
if (!StrongRefToThisCaptured && // XXX: Do we want to make sure that this type which we are capturing is a
Capture.capturesVariable() && // "Smart Pointer" somehow?
if (!StrongRefToThisCaptured && Capture.capturesVariable() &&
Capture.getCaptureKind() == LCK_ByCopy) { Capture.getCaptureKind() == LCK_ByCopy) {
const VarDecl *Var = Capture.getCapturedVar(); const VarDecl *Var = Capture.getCapturedVar();
if (Var->hasInit()) { if (Var->hasInit()) {
@@ -103,13 +103,15 @@ void RefCountedInsideLambdaChecker::check(
} }
} }
// Now we can go through and produce errors for any captured variables or this pointers. // Now we can go through and produce errors for any captured variables or this
// pointers.
for (const LambdaCapture &Capture : Lambda->captures()) { for (const LambdaCapture &Capture : Lambda->captures()) {
if (Capture.capturesVariable()) { if (Capture.capturesVariable()) {
QualType Pointee = Capture.getCapturedVar()->getType()->getPointeeType(); QualType Pointee = Capture.getCapturedVar()->getType()->getPointeeType();
if (!Pointee.isNull() && isClassRefCounted(Pointee)) { if (!Pointee.isNull() && isClassRefCounted(Pointee)) {
emitDiagnostics(Capture.getLocation(), Capture.getCapturedVar()->getName(), Pointee); emitDiagnostics(Capture.getLocation(),
Capture.getCapturedVar()->getName(), Pointee);
return; return;
} }
} }
@@ -126,11 +128,11 @@ void RefCountedInsideLambdaChecker::check(
// expresses the intent that the lambda won't leave the enclosing scope. // expresses the intent that the lambda won't leave the enclosing scope.
bool ImplicitByRefDefaultedCapture = bool ImplicitByRefDefaultedCapture =
Capture.isImplicit() && Lambda->getLambdaCaptureDefault() == LCD_ByRef; Capture.isImplicit() && Lambda->getLambdaCaptureDefault() == LCD_ByRef;
if (Capture.capturesThis() && if (Capture.capturesThis() && !ImplicitByRefDefaultedCapture &&
!ImplicitByRefDefaultedCapture &&
!StrongRefToThisCaptured) { !StrongRefToThisCaptured) {
ThisVisitor V(*this); ThisVisitor V(*this);
bool NotAborted = V.TraverseDecl(const_cast<CXXMethodDecl *>(Lambda->getLambdaCallOperator())); bool NotAborted = V.TraverseDecl(
const_cast<CXXMethodDecl *>(Lambda->getLambdaCallOperator()));
if (!NotAborted) { if (!NotAborted) {
return; return;
} }
@@ -138,7 +140,8 @@ void RefCountedInsideLambdaChecker::check(
} }
} }
bool RefCountedInsideLambdaChecker::ThisVisitor::VisitCXXThisExpr(CXXThisExpr *This) { bool RefCountedInsideLambdaChecker::ThisVisitor::VisitCXXThisExpr(
CXXThisExpr *This) {
QualType Pointee = This->getType()->getPointeeType(); QualType Pointee = This->getType()->getPointeeType();
if (!Pointee.isNull() && isClassRefCounted(Pointee)) { if (!Pointee.isNull() && isClassRefCounted(Pointee)) {
Checker.emitDiagnostics(This->getLocStart(), "this", Pointee); Checker.emitDiagnostics(This->getLocStart(), "this", Pointee);

View File

@@ -24,6 +24,7 @@ private:
: Checker(Checker) {} : Checker(Checker) {}
bool VisitCXXThisExpr(CXXThisExpr *This); bool VisitCXXThisExpr(CXXThisExpr *This);
private: private:
RefCountedInsideLambdaChecker &Checker; RefCountedInsideLambdaChecker &Checker;
}; };

View File

@@ -10,8 +10,7 @@ void ScopeChecker::registerMatchers(MatchFinder* AstMatcher) {
AstMatcher->addMatcher(cxxNewExpr().bind("node"), this); AstMatcher->addMatcher(cxxNewExpr().bind("node"), this);
AstMatcher->addMatcher(materializeTemporaryExpr().bind("node"), this); AstMatcher->addMatcher(materializeTemporaryExpr().bind("node"), this);
AstMatcher->addMatcher( AstMatcher->addMatcher(
callExpr(callee(functionDecl(heapAllocator()))).bind("node"), callExpr(callee(functionDecl(heapAllocator()))).bind("node"), this);
this);
AstMatcher->addMatcher(parmVarDecl().bind("parm_vardecl"), this); AstMatcher->addMatcher(parmVarDecl().bind("parm_vardecl"), this);
} }
@@ -31,8 +30,7 @@ typedef DenseMap<const MaterializeTemporaryExpr *, const Decl *>
AutomaticTemporaryMap; AutomaticTemporaryMap;
AutomaticTemporaryMap AutomaticTemporaries; AutomaticTemporaryMap AutomaticTemporaries;
void ScopeChecker::check( void ScopeChecker::check(const MatchFinder::MatchResult &Result) {
const MatchFinder::MatchResult &Result) {
// There are a variety of different reasons why something could be allocated // There are a variety of different reasons why something could be allocated
AllocationVariety Variety = AV_None; AllocationVariety Variety = AV_None;
SourceLocation Loc; SourceLocation Loc;
@@ -120,25 +118,17 @@ void ScopeChecker::check(
} }
// Error messages for incorrect allocations. // Error messages for incorrect allocations.
const char* Stack = const char *Stack = "variable of type %0 only valid on the stack";
"variable of type %0 only valid on the stack"; const char *Global = "variable of type %0 only valid as global";
const char* Global = const char *Heap = "variable of type %0 only valid on the heap";
"variable of type %0 only valid as global"; const char *NonHeap = "variable of type %0 is not valid on the heap";
const char* Heap = const char *NonTemporary = "variable of type %0 is not valid in a temporary";
"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";
const char *StackNote = const char *StackNote =
"value incorrectly allocated in an automatic variable"; "value incorrectly allocated in an automatic variable";
const char* GlobalNote = const char *GlobalNote = "value incorrectly allocated in a global variable";
"value incorrectly allocated in a global variable"; const char *HeapNote = "value incorrectly allocated on the heap";
const char* HeapNote = const char *TemporaryNote = "value incorrectly allocated in a temporary";
"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. // Report errors depending on the annotations on the input types.
switch (Variety) { switch (Variety) {

View File

@@ -7,19 +7,22 @@
void SprintfLiteralChecker::registerMatchers(MatchFinder *AstMatcher) { void SprintfLiteralChecker::registerMatchers(MatchFinder *AstMatcher) {
AstMatcher->addMatcher( AstMatcher->addMatcher(
callExpr(isSnprintfLikeFunc(), callExpr(
allOf(hasArgument(0, ignoringParenImpCasts(declRefExpr().bind("buffer"))), isSnprintfLikeFunc(),
anyOf(hasArgument(1, sizeOfExpr(hasIgnoringParenImpCasts(declRefExpr().bind("size")))), allOf(hasArgument(
0, ignoringParenImpCasts(declRefExpr().bind("buffer"))),
anyOf(hasArgument(1, sizeOfExpr(hasIgnoringParenImpCasts(
declRefExpr().bind("size")))),
hasArgument(1, integerLiteral().bind("immediate")), hasArgument(1, integerLiteral().bind("immediate")),
hasArgument(1, declRefExpr(to(varDecl(hasType(isConstQualified()), hasArgument(1, declRefExpr(to(varDecl(
hasInitializer(integerLiteral().bind("constant"))))))))) hasType(isConstQualified()),
hasInitializer(integerLiteral().bind(
"constant")))))))))
.bind("funcCall"), .bind("funcCall"),
this this);
);
} }
void SprintfLiteralChecker::check( void SprintfLiteralChecker::check(const MatchFinder::MatchResult &Result) {
const MatchFinder::MatchResult &Result) {
if (!Result.Context->getLangOpts().CPlusPlus) { if (!Result.Context->getLangOpts().CPlusPlus) {
// SprintfLiteral is not usable in C, so there is no point in issuing these // SprintfLiteral is not usable in C, so there is no point in issuing these
// warnings. // warnings.
@@ -56,21 +59,25 @@ void SprintfLiteralChecker::check(
} }
const QualType QType = Buffer->getType(); const QualType QType = Buffer->getType();
const ConstantArrayType *Type = dyn_cast<ConstantArrayType>(QType.getTypePtrOrNull()); const ConstantArrayType *Type =
dyn_cast<ConstantArrayType>(QType.getTypePtrOrNull());
if (Type) { if (Type) {
// Match calls like snprintf(x, 100, ...), where x is int[100]; // Match calls like snprintf(x, 100, ...), where x is int[100];
const IntegerLiteral *Literal = Result.Nodes.getNodeAs<IntegerLiteral>("immediate"); const IntegerLiteral *Literal =
Result.Nodes.getNodeAs<IntegerLiteral>("immediate");
if (!Literal) { if (!Literal) {
// Match calls like: const int y = 100; snprintf(x, y, ...); // Match calls like: const int y = 100; snprintf(x, y, ...);
Literal = Result.Nodes.getNodeAs<IntegerLiteral>("constant"); Literal = Result.Nodes.getNodeAs<IntegerLiteral>("constant");
} }
// We're going to assume here that the bitwidth of both of these values fits within 64 bits. // We're going to assume here that the bitwidth of both of these values fits
// and zero-extend both values to 64-bits before comparing them. // within 64 bits. and zero-extend both values to 64-bits before comparing
// them.
uint64_t Size = Type->getSize().getZExtValue(); uint64_t Size = Type->getSize().getZExtValue();
uint64_t Lit = Literal->getValue().getZExtValue(); uint64_t Lit = Literal->getValue().getZExtValue();
if (Size <= Lit) { if (Size <= Lit) {
diag(D->getLocStart(), Error, DiagnosticIDs::Error) << Name << Replacement; diag(D->getLocStart(), Error, DiagnosticIDs::Error)
<< Name << Replacement;
diag(D->getLocStart(), Note, DiagnosticIDs::Note) << Name; diag(D->getLocStart(), Note, DiagnosticIDs::Note) << Name;
} }
} }

View File

@@ -9,8 +9,7 @@
class SprintfLiteralChecker : public BaseCheck { class SprintfLiteralChecker : public BaseCheck {
public: public:
SprintfLiteralChecker(StringRef CheckName, SprintfLiteralChecker(StringRef CheckName, ContextType *Context = nullptr)
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {} : BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override; void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override; void check(const MatchFinder::MatchResult &Result) override;

View File

@@ -38,7 +38,8 @@ inline SmallVector<const Stmt *, 1> getParentStmts(const Stmt *S,
return Result; return Result;
} }
// This class is a modified version of the class from clang-tidy's ExprSequence.cpp // This class is a modified version of the class from clang-tidy's
// ExprSequence.cpp
// //
// Maps `Stmt`s to the `CFGBlock` that contains them. Some `Stmt`s may be // Maps `Stmt`s to the `CFGBlock` that contains them. Some `Stmt`s may be
// contained in more than one `CFGBlock`; in this case, they are mapped to the // contained in more than one `CFGBlock`; in this case, they are mapped to the
@@ -48,7 +49,8 @@ inline SmallVector<const Stmt *, 1> getParentStmts(const Stmt *S,
class StmtToBlockMap { class StmtToBlockMap {
public: public:
// Initializes the map for the given `CFG`. // Initializes the map for the given `CFG`.
StmtToBlockMap(const CFG *TheCFG, ASTContext *TheContext) : Context(TheContext) { StmtToBlockMap(const CFG *TheCFG, ASTContext *TheContext)
: Context(TheContext) {
for (const auto *B : *TheCFG) { for (const auto *B : *TheCFG) {
for (size_t I = 0; I < B->size(); ++I) { for (size_t I = 0; I < B->size(); ++I) {
if (Optional<CFGStmt> S = (*B)[I].getAs<CFGStmt>()) { if (Optional<CFGStmt> S = (*B)[I].getAs<CFGStmt>()) {
@@ -64,7 +66,8 @@ public:
// //
// The optional outparameter `Index` is set to the index into the block where // The optional outparameter `Index` is set to the index into the block where
// the `Stmt` was found. // the `Stmt` was found.
const CFGBlock *blockContainingStmt(const Stmt *S, size_t *Index = nullptr) const { const CFGBlock *blockContainingStmt(const Stmt *S,
size_t *Index = nullptr) const {
while (!Map.count(S)) { while (!Map.count(S)) {
SmallVector<const Stmt *, 1> Parents = getParentStmts(S, Context); SmallVector<const Stmt *, 1> Parents = getParentStmts(S, Context);
if (Parents.empty()) if (Parents.empty())
@@ -73,7 +76,8 @@ public:
} }
const auto &E = Map.lookup(S); const auto &E = Map.lookup(S);
if (Index) *Index = E.second; if (Index)
*Index = E.second;
return E.first; return E.first;
} }

View File

@@ -10,10 +10,8 @@ void TrivialCtorDtorChecker::registerMatchers(MatchFinder* AstMatcher) {
this); this);
} }
void TrivialCtorDtorChecker::check( void TrivialCtorDtorChecker::check(const MatchFinder::MatchResult &Result) {
const MatchFinder::MatchResult &Result) { const char *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"); const CXXRecordDecl *Node = Result.Nodes.getNodeAs<CXXRecordDecl>("node");
if (!Node->hasDefinition()) { if (!Node->hasDefinition()) {

View File

@@ -9,8 +9,7 @@
class TrivialCtorDtorChecker : public BaseCheck { class TrivialCtorDtorChecker : public BaseCheck {
public: public:
TrivialCtorDtorChecker(StringRef CheckName, TrivialCtorDtorChecker(StringRef CheckName, ContextType *Context = nullptr)
ContextType *Context = nullptr)
: BaseCheck(CheckName, Context) {} : BaseCheck(CheckName, Context) {}
void registerMatchers(MatchFinder *AstMatcher) override; void registerMatchers(MatchFinder *AstMatcher) override;
void check(const MatchFinder::MatchResult &Result) override; void check(const MatchFinder::MatchResult &Result) override;

View File

@@ -472,7 +472,8 @@ inline bool isInfixBinaryOp(const CXXOperatorCallExpr* OpCall) {
return false; return false;
switch (OpCall->getOperator()) { switch (OpCall->getOperator()) {
case OO_Call: case OO_Subscript: case OO_Call:
case OO_Subscript:
return false; return false;
default: default:
return true; return true;
@@ -480,5 +481,4 @@ inline bool isInfixBinaryOp(const CXXOperatorCallExpr* OpCall) {
#endif #endif
} }
#endif #endif

View File

@@ -1,8 +1,7 @@
#include "VariableUsageHelpers.h" #include "VariableUsageHelpers.h"
#include "Utils.h" #include "Utils.h"
std::vector<const Stmt*> std::vector<const Stmt *> getUsageAsRvalue(const ValueDecl *ValueDeclaration,
getUsageAsRvalue(const ValueDecl* ValueDeclaration,
const FunctionDecl *FuncDecl) { const FunctionDecl *FuncDecl) {
std::vector<const Stmt *> UsageStatements; std::vector<const Stmt *> UsageStatements;
@@ -14,9 +13,8 @@ getUsageAsRvalue(const ValueDecl* ValueDeclaration,
// We build a Control Flow Graph (CFG) fron the body of the function // We build a Control Flow Graph (CFG) fron the body of the function
// declaration. // declaration.
std::unique_ptr<CFG> StatementCFG std::unique_ptr<CFG> StatementCFG = CFG::buildCFG(
= CFG::buildCFG(FuncDecl, Body, &FuncDecl->getASTContext(), FuncDecl, Body, &FuncDecl->getASTContext(), CFG::BuildOptions());
CFG::BuildOptions());
// We iterate through all the CFGBlocks, which basically means that we go over // We iterate through all the CFGBlocks, which basically means that we go over
// all the possible branches of the code and therefore cover all statements. // all the possible branches of the code and therefore cover all statements.
@@ -71,30 +69,24 @@ getUsageAsRvalue(const ValueDecl* ValueDeclaration,
} }
// We declare our EscapesFunctionError enum to be an error code enum. // We declare our EscapesFunctionError enum to be an error code enum.
namespace std namespace std {
{ template <> struct is_error_code_enum<EscapesFunctionError> : true_type {};
template <> } // namespace std
struct is_error_code_enum<EscapesFunctionError> : true_type {};
}
// We define the EscapesFunctionErrorCategory which contains the error messages // We define the EscapesFunctionErrorCategory which contains the error messages
// corresponding to each enum variant. // corresponding to each enum variant.
namespace { namespace {
struct EscapesFunctionErrorCategory : std::error_category struct EscapesFunctionErrorCategory : std::error_category {
{
const char *name() const noexcept override; const char *name() const noexcept override;
std::string message(int ev) const override; std::string message(int ev) const override;
}; };
const char* EscapesFunctionErrorCategory::name() const noexcept const char *EscapesFunctionErrorCategory::name() const noexcept {
{
return "escapes function"; return "escapes function";
} }
std::string EscapesFunctionErrorCategory::message(int ev) const std::string EscapesFunctionErrorCategory::message(int ev) const {
{ switch (static_cast<EscapesFunctionError>(ev)) {
switch (static_cast<EscapesFunctionError>(ev))
{
case EscapesFunctionError::ConstructorDeclNotFound: case EscapesFunctionError::ConstructorDeclNotFound:
return "constructor declaration not found"; return "constructor declaration not found";
@@ -119,10 +111,9 @@ namespace {
} }
const EscapesFunctionErrorCategory TheEscapesFunctionErrorCategory{}; const EscapesFunctionErrorCategory TheEscapesFunctionErrorCategory{};
} } // namespace
std::error_code make_error_code(EscapesFunctionError e) std::error_code make_error_code(EscapesFunctionError e) {
{
return {static_cast<int>(e), TheEscapesFunctionErrorCategory}; return {static_cast<int>(e), TheEscapesFunctionErrorCategory};
} }
@@ -256,7 +247,8 @@ escapesFunction(const Expr* Arg, const FunctionDecl *FuncDecl,
} }
return std::make_tuple(Usage, (const Decl *)VarDeclaration); return std::make_tuple(Usage, (const Decl *)VarDeclaration);
} else if (auto FieldDeclaration = dyn_cast<FieldDecl>(DeclRef->getDecl())) { } else if (auto FieldDeclaration =
dyn_cast<FieldDecl>(DeclRef->getDecl())) {
// This is the case where the parameter escapes through a field. // This is the case where the parameter escapes through a field.
return std::make_tuple(Usage, (const Decl *)FieldDeclaration); return std::make_tuple(Usage, (const Decl *)FieldDeclaration);
@@ -264,8 +256,8 @@ escapesFunction(const Expr* Arg, const FunctionDecl *FuncDecl,
} else if (isa<ReturnStmt>(Usage)) { } else if (isa<ReturnStmt>(Usage)) {
// This is the case where the parameter escapes through the return value // This is the case where the parameter escapes through the return value
// of the function. // of the function.
if (!FuncDecl->getReturnType()->isPointerType() if (!FuncDecl->getReturnType()->isPointerType() &&
&& !FuncDecl->getReturnType()->isReferenceType()) { !FuncDecl->getReturnType()->isReferenceType()) {
continue; continue;
} }

View File

@@ -2,7 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef VariableUsageHelpers_h__ #ifndef VariableUsageHelpers_h__
#define VariableUsageHelpers_h__ #define VariableUsageHelpers_h__
@@ -14,8 +13,7 @@
/// WARNING: incomplete behaviour/implementation for general-purpose use outside /// WARNING: incomplete behaviour/implementation for general-purpose use outside
/// of escapesFunction(). This only detects very basic usages (see /// of escapesFunction(). This only detects very basic usages (see
/// implementation for more details). /// implementation for more details).
std::vector<const Stmt*> std::vector<const Stmt *> getUsageAsRvalue(const ValueDecl *ValueDeclaration,
getUsageAsRvalue(const ValueDecl* ValueDeclaration,
const FunctionDecl *FuncDecl); const FunctionDecl *FuncDecl);
/// This is the error enumeration for escapesFunction(), describing all the /// This is the error enumeration for escapesFunction(), describing all the

View File

@@ -5,12 +5,12 @@
#ifndef plugin_h__ #ifndef plugin_h__
#define plugin_h__ #define plugin_h__
#include "clang/Analysis/CFG.h"
#include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h" #include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/RecursiveASTVisitor.h"
#include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Analysis/CFG.h"
#include "clang/Basic/Version.h" #include "clang/Basic/Version.h"
#include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/MultiplexConsumer.h" #include "clang/Frontend/MultiplexConsumer.h"
@@ -18,8 +18,8 @@
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/Support/FileSystem.h" #include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h" #include "llvm/Support/Path.h"
#include <memory>
#include <iterator> #include <iterator>
#include <memory>
#define CLANG_VERSION_FULL (CLANG_VERSION_MAJOR * 100 + CLANG_VERSION_MINOR) #define CLANG_VERSION_FULL (CLANG_VERSION_MAJOR * 100 + CLANG_VERSION_MINOR)
@@ -54,9 +54,9 @@ typedef ASTConsumer *ASTConsumerPtr;
#endif #endif
// In order to support running our checks using clang-tidy, we implement a source // In order to support running our checks using clang-tidy, we implement a
// compatible base check class called BaseCheck, and we use the preprocessor to // source compatible base check class called BaseCheck, and we use the
// decide which base class to pick. // preprocessor to decide which base class to pick.
#ifdef CLANG_TIDY #ifdef CLANG_TIDY
#include "../ClangTidy.h" #include "../ClangTidy.h"
typedef clang::tidy::ClangTidyCheck BaseCheck; typedef clang::tidy::ClangTidyCheck BaseCheck;