зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1615826 - Reformat `clang-plugin` to LLVM standard. r=froydnj
Differential Revision: https://phabricator.services.mozilla.com/D63000 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
4cbe8542ac
Коммит
e67b41e3c7
|
@ -55,13 +55,11 @@
|
|||
void CanRunScriptChecker::registerMatchers(MatchFinder *AstMatcher) {
|
||||
auto Refcounted = qualType(hasDeclaration(cxxRecordDecl(isRefCounted())));
|
||||
auto StackSmartPtr =
|
||||
ignoreTrivials(
|
||||
declRefExpr(to(varDecl(hasAutomaticStorageDuration())),
|
||||
hasType(isSmartPtrToRefCounted())));
|
||||
ignoreTrivials(declRefExpr(to(varDecl(hasAutomaticStorageDuration())),
|
||||
hasType(isSmartPtrToRefCounted())));
|
||||
auto ConstMemberOfThisSmartPtr =
|
||||
memberExpr(hasType(isSmartPtrToRefCounted()),
|
||||
hasType(isConstQualified()),
|
||||
hasObjectExpression(cxxThisExpr()));
|
||||
memberExpr(hasType(isSmartPtrToRefCounted()), hasType(isConstQualified()),
|
||||
hasObjectExpression(cxxThisExpr()));
|
||||
// A smartptr can be known-live for three reasons:
|
||||
// 1) It's declared on the stack.
|
||||
// 2) It's a const member of "this". We know "this" is alive (recursively)
|
||||
|
@ -70,15 +68,14 @@ void CanRunScriptChecker::registerMatchers(MatchFinder *AstMatcher) {
|
|||
// 3) It's an immediate temporary being constructed at the point where the
|
||||
// call is happening.
|
||||
auto KnownLiveSmartPtr = anyOf(
|
||||
StackSmartPtr,
|
||||
ConstMemberOfThisSmartPtr,
|
||||
ignoreTrivials(cxxConstructExpr(hasType(isSmartPtrToRefCounted()))));
|
||||
StackSmartPtr, ConstMemberOfThisSmartPtr,
|
||||
ignoreTrivials(cxxConstructExpr(hasType(isSmartPtrToRefCounted()))));
|
||||
|
||||
auto MozKnownLiveCall =
|
||||
ignoreTrivials(callExpr(callee(functionDecl(hasName("MOZ_KnownLive")))));
|
||||
ignoreTrivials(callExpr(callee(functionDecl(hasName("MOZ_KnownLive")))));
|
||||
|
||||
// Params of the calling function are presumed live, because it itself should be
|
||||
// MOZ_CAN_RUN_SCRIPT. Note that this is subject to
|
||||
// Params of the calling function are presumed live, because it itself should
|
||||
// be MOZ_CAN_RUN_SCRIPT. Note that this is subject to
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1537656 a the moment.
|
||||
auto KnownLiveParam = anyOf(
|
||||
// "this" is OK
|
||||
|
@ -108,15 +105,12 @@ void CanRunScriptChecker::registerMatchers(MatchFinder *AstMatcher) {
|
|||
// return non-live objects (e.g. consider "live_pointer->foo()" as an
|
||||
// example). For purposes of this analysis we are assuming the method
|
||||
// calls on smart ptrs all just return the pointer inside,
|
||||
cxxMemberCallExpr(on(
|
||||
allOf(hasType(isSmartPtrToRefCounted()),
|
||||
KnownLiveBase))),
|
||||
cxxMemberCallExpr(
|
||||
on(allOf(hasType(isSmartPtrToRefCounted()), KnownLiveBase))),
|
||||
// operator* or operator-> on a thing that is already known to be live.
|
||||
cxxOperatorCallExpr(
|
||||
anyOf(hasOverloadedOperatorName("*"),
|
||||
hasOverloadedOperatorName("->")),
|
||||
hasAnyArgument(KnownLiveBase),
|
||||
argumentCountIs(1)),
|
||||
cxxOperatorCallExpr(anyOf(hasOverloadedOperatorName("*"),
|
||||
hasOverloadedOperatorName("->")),
|
||||
hasAnyArgument(KnownLiveBase), argumentCountIs(1)),
|
||||
// A dereference on a thing that is known to be live. This is _not_
|
||||
// caught by the "operator* or operator->" clause above, because
|
||||
// cxxOperatorCallExpr() only catches cases when a class defines
|
||||
|
@ -139,47 +133,36 @@ void CanRunScriptChecker::registerMatchers(MatchFinder *AstMatcher) {
|
|||
// does not guarantee liveness; in fact the callee could modify those
|
||||
// things! In practice they would be the wrong type anyway, though, so
|
||||
// it's hard to add a test for this.
|
||||
unaryOperator(
|
||||
hasOperatorName("&"),
|
||||
hasUnaryOperand(allOf(
|
||||
anyOf(
|
||||
hasType(references(Refcounted)),
|
||||
hasType(Refcounted)),
|
||||
ignoreTrivials(KnownLiveBase))))
|
||||
);
|
||||
unaryOperator(hasOperatorName("&"),
|
||||
hasUnaryOperand(allOf(anyOf(hasType(references(Refcounted)),
|
||||
hasType(Refcounted)),
|
||||
ignoreTrivials(KnownLiveBase)))));
|
||||
|
||||
auto KnownLive = anyOf(
|
||||
// Anything above, of course.
|
||||
KnownLiveSimple,
|
||||
// Conditional operators where both arms are live.
|
||||
conditionalOperator(
|
||||
hasFalseExpression(ignoreTrivials(KnownLiveSimple)),
|
||||
hasTrueExpression(ignoreTrivials(KnownLiveSimple)))
|
||||
conditionalOperator(hasFalseExpression(ignoreTrivials(KnownLiveSimple)),
|
||||
hasTrueExpression(ignoreTrivials(KnownLiveSimple)))
|
||||
// We're not handling cases like a dereference of a conditional operator,
|
||||
// mostly because handling a dereference in general is so ugly. I
|
||||
// _really_ wish I could just write a recursive matcher here easily.
|
||||
);
|
||||
);
|
||||
|
||||
auto InvalidArg =
|
||||
ignoreTrivialsConditional(
|
||||
// We want to consider things if there is anything refcounted involved,
|
||||
// including in any of the trivials that we otherwise strip off.
|
||||
anyOf(
|
||||
hasType(Refcounted),
|
||||
hasType(pointsTo(Refcounted)),
|
||||
hasType(references(Refcounted)),
|
||||
hasType(isSmartPtrToRefCounted())
|
||||
),
|
||||
// We want to find any expression,
|
||||
expr(
|
||||
auto InvalidArg = ignoreTrivialsConditional(
|
||||
// We want to consider things if there is anything refcounted involved,
|
||||
// including in any of the trivials that we otherwise strip off.
|
||||
anyOf(hasType(Refcounted), hasType(pointsTo(Refcounted)),
|
||||
hasType(references(Refcounted)), hasType(isSmartPtrToRefCounted())),
|
||||
// We want to find any expression,
|
||||
expr(
|
||||
// which is not known live,
|
||||
unless(KnownLive),
|
||||
// and which is not a default arg with value nullptr, since those are
|
||||
// always safe,
|
||||
unless(cxxDefaultArgExpr(isNullDefaultArg())),
|
||||
// and which is not a literal nullptr,
|
||||
unless(cxxNullPtrLiteralExpr()),
|
||||
expr().bind("invalidArg")));
|
||||
unless(cxxNullPtrLiteralExpr()), expr().bind("invalidArg")));
|
||||
|
||||
// A matcher which will mark the first invalid argument it finds invalid, but
|
||||
// will always match, even if it finds no invalid arguments, so it doesn't
|
||||
|
@ -203,11 +186,7 @@ void CanRunScriptChecker::registerMatchers(MatchFinder *AstMatcher) {
|
|||
// which optionally has an invalid arg,
|
||||
OptionalInvalidExplicitArg,
|
||||
// or which optionally has an invalid this argument,
|
||||
anyOf(
|
||||
on(InvalidArg),
|
||||
anything()
|
||||
),
|
||||
expr().bind("callExpr")),
|
||||
anyOf(on(InvalidArg), anything()), expr().bind("callExpr")),
|
||||
// or a regular call expression,
|
||||
callExpr(
|
||||
// which optionally has an invalid arg.
|
||||
|
@ -238,10 +217,9 @@ namespace {
|
|||
/// any) also have the annotation.
|
||||
class FuncSetCallback : public MatchFinder::MatchCallback {
|
||||
public:
|
||||
FuncSetCallback(CanRunScriptChecker& Checker,
|
||||
FuncSetCallback(CanRunScriptChecker &Checker,
|
||||
std::unordered_set<const FunctionDecl *> &FuncSet)
|
||||
: CanRunScriptFuncs(FuncSet),
|
||||
Checker(Checker) {}
|
||||
: CanRunScriptFuncs(FuncSet), Checker(Checker) {}
|
||||
|
||||
void run(const MatchFinder::MatchResult &Result) override;
|
||||
|
||||
|
@ -277,14 +255,13 @@ void FuncSetCallback::checkOverriddenMethods(const CXXMethodDecl *Method) {
|
|||
const char *ErrorNonCanRunScriptOverridden =
|
||||
"functions marked as MOZ_CAN_RUN_SCRIPT cannot override functions "
|
||||
"that are not marked MOZ_CAN_RUN_SCRIPT";
|
||||
const char* NoteNonCanRunScriptOverridden =
|
||||
const char *NoteNonCanRunScriptOverridden =
|
||||
"overridden function declared here";
|
||||
|
||||
Checker.diag(Method->getLocation(), ErrorNonCanRunScriptOverridden,
|
||||
DiagnosticIDs::Error);
|
||||
Checker.diag(OverriddenMethod->getLocation(),
|
||||
NoteNonCanRunScriptOverridden,
|
||||
DiagnosticIDs::Note);
|
||||
NoteNonCanRunScriptOverridden, DiagnosticIDs::Note);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -300,9 +277,7 @@ void CanRunScriptChecker::buildFuncSet(ASTContext *Context) {
|
|||
Finder.addMatcher(
|
||||
functionDecl(hasCanRunScriptAnnotation()).bind("canRunScriptFunction"),
|
||||
&Callback);
|
||||
Finder.addMatcher(
|
||||
lambdaExpr().bind("lambda"),
|
||||
&Callback);
|
||||
Finder.addMatcher(lambdaExpr().bind("lambda"), &Callback);
|
||||
// We start the analysis, given the ASTContext our main checker is in.
|
||||
Finder.matchAST(*Context);
|
||||
}
|
||||
|
@ -327,7 +302,7 @@ void CanRunScriptChecker::check(const MatchFinder::MatchResult &Result) {
|
|||
const char *NoteNonCanRunScriptParent = "caller function declared here";
|
||||
|
||||
const Expr *InvalidArg;
|
||||
if (const CXXDefaultArgExpr* defaultArg =
|
||||
if (const CXXDefaultArgExpr *defaultArg =
|
||||
Result.Nodes.getNodeAs<CXXDefaultArgExpr>("invalidArg")) {
|
||||
InvalidArg = defaultArg->getExpr();
|
||||
} else {
|
||||
|
@ -383,11 +358,9 @@ void CanRunScriptChecker::check(const MatchFinder::MatchResult &Result) {
|
|||
// If we have an invalid argument in the call, we emit the diagnostic to
|
||||
// signal it.
|
||||
if (InvalidArg) {
|
||||
const std::string invalidArgText =
|
||||
Lexer::getSourceText(
|
||||
CharSourceRange::getTokenRange(InvalidArg->getSourceRange()),
|
||||
Result.Context->getSourceManager(),
|
||||
Result.Context->getLangOpts());
|
||||
const std::string invalidArgText = Lexer::getSourceText(
|
||||
CharSourceRange::getTokenRange(InvalidArg->getSourceRange()),
|
||||
Result.Context->getSourceManager(), Result.Context->getLangOpts());
|
||||
diag(InvalidArg->getExprLoc(), ErrorInvalidArg, DiagnosticIDs::Error)
|
||||
<< InvalidArg->getSourceRange() << invalidArgText;
|
||||
}
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
* 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 <algorithm>
|
||||
#include "CustomAttributes.h"
|
||||
#include "plugin.h"
|
||||
#include "clang/Frontend/FrontendPluginRegistry.h"
|
||||
#include <algorithm>
|
||||
|
||||
/* Having annotations in the AST unexpectedly impacts codegen.
|
||||
* Ideally, we'd avoid having annotations at all, by using an API such as
|
||||
|
@ -26,37 +26,34 @@
|
|||
using namespace clang;
|
||||
using namespace llvm;
|
||||
|
||||
static DenseMap<const Decl*, CustomAttributesSet> AttributesCache;
|
||||
static DenseMap<const Decl *, CustomAttributesSet> AttributesCache;
|
||||
|
||||
static CustomAttributesSet CacheAttributes(const Decl* D)
|
||||
{
|
||||
static CustomAttributesSet CacheAttributes(const Decl *D) {
|
||||
CustomAttributesSet attrs = {};
|
||||
for (auto Attr : D->specific_attrs<AnnotateAttr>()) {
|
||||
auto annotation = Attr->getAnnotation();
|
||||
#define ATTR(a) \
|
||||
if (annotation == #a) { \
|
||||
attrs.has_ ## a = true; \
|
||||
} else
|
||||
#define ATTR(a) \
|
||||
if (annotation == #a) { \
|
||||
attrs.has_##a = true; \
|
||||
} else
|
||||
#include "CustomAttributes.inc"
|
||||
#undef ATTR
|
||||
{}
|
||||
}
|
||||
const_cast<Decl*>(D)->dropAttr<AnnotateAttr>();
|
||||
const_cast<Decl *>(D)->dropAttr<AnnotateAttr>();
|
||||
AttributesCache.insert(std::make_pair(D, attrs));
|
||||
return attrs;
|
||||
}
|
||||
|
||||
static void Report(const Decl* D, const char* message)
|
||||
{
|
||||
ASTContext& Context = D->getASTContext();
|
||||
DiagnosticsEngine& Diag = Context.getDiagnostics();
|
||||
unsigned ID = Diag.getDiagnosticIDs()->getCustomDiagID(
|
||||
DiagnosticIDs::Warning, message);
|
||||
static void Report(const Decl *D, const char *message) {
|
||||
ASTContext &Context = D->getASTContext();
|
||||
DiagnosticsEngine &Diag = Context.getDiagnostics();
|
||||
unsigned ID =
|
||||
Diag.getDiagnosticIDs()->getCustomDiagID(DiagnosticIDs::Warning, message);
|
||||
Diag.Report(D->getBeginLoc(), ID);
|
||||
}
|
||||
|
||||
CustomAttributesSet GetAttributes(const Decl* D)
|
||||
{
|
||||
CustomAttributesSet GetAttributes(const Decl *D) {
|
||||
CustomAttributesSet attrs = {};
|
||||
if (D->hasAttr<AnnotateAttr>()) {
|
||||
Report(D, "Declaration has unhandled annotations.");
|
||||
|
@ -70,22 +67,22 @@ CustomAttributesSet GetAttributes(const Decl* D)
|
|||
return attrs;
|
||||
}
|
||||
|
||||
bool hasCustomAttribute(const clang::Decl* D, CustomAttributes A)
|
||||
{
|
||||
bool hasCustomAttribute(const clang::Decl *D, CustomAttributes A) {
|
||||
CustomAttributesSet attrs = GetAttributes(D);
|
||||
switch (A) {
|
||||
#define ATTR(a) case a: return attrs.has_ ## a;
|
||||
#define ATTR(a) \
|
||||
case a: \
|
||||
return attrs.has_##a;
|
||||
#include "CustomAttributes.inc"
|
||||
#undef ATTR
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class CustomAttributesMatcher : public ast_matchers::MatchFinder::MatchCallback {
|
||||
class CustomAttributesMatcher
|
||||
: public ast_matchers::MatchFinder::MatchCallback {
|
||||
public:
|
||||
virtual void
|
||||
run(const ast_matchers::MatchFinder::MatchResult &Result) final
|
||||
{
|
||||
void run(const ast_matchers::MatchFinder::MatchResult &Result) final {
|
||||
if (auto D = Result.Nodes.getNodeAs<Decl>("decl")) {
|
||||
CacheAttributes(D);
|
||||
} else if (auto L = Result.Nodes.getNodeAs<LambdaExpr>("lambda")) {
|
||||
|
@ -99,9 +96,10 @@ class CustomAttributesAction : public PluginASTAction {
|
|||
public:
|
||||
ASTConsumerPtr CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef FileName) override {
|
||||
auto& Context = CI.getASTContext();
|
||||
auto &Context = CI.getASTContext();
|
||||
auto AstMatcher = new (Context.Allocate<MatchFinder>()) MatchFinder();
|
||||
auto Matcher = new (Context.Allocate<CustomAttributesMatcher>()) CustomAttributesMatcher();
|
||||
auto Matcher = new (Context.Allocate<CustomAttributesMatcher>())
|
||||
CustomAttributesMatcher();
|
||||
AstMatcher->addMatcher(decl().bind("decl"), Matcher);
|
||||
AstMatcher->addMatcher(lambdaExpr().bind("lambda"), Matcher);
|
||||
return AstMatcher->newASTConsumer();
|
||||
|
@ -112,11 +110,8 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
ActionType getActionType() override {
|
||||
return AddBeforeMainAction;
|
||||
}
|
||||
ActionType getActionType() override { return AddBeforeMainAction; }
|
||||
};
|
||||
|
||||
static FrontendPluginRegistry::Add<CustomAttributesAction> X(
|
||||
"moz-custom-attributes",
|
||||
"prepare custom attributes for moz-check");
|
||||
static FrontendPluginRegistry::Add<CustomAttributesAction>
|
||||
X("moz-custom-attributes", "prepare custom attributes for moz-check");
|
||||
|
|
|
@ -15,26 +15,24 @@ enum CustomAttributes {
|
|||
};
|
||||
|
||||
struct CustomAttributesSet {
|
||||
#define ATTR(a) bool has_ ## a: 1;
|
||||
#define ATTR(a) bool has_##a : 1;
|
||||
#include "CustomAttributes.inc"
|
||||
#undef ATTR
|
||||
};
|
||||
|
||||
template<CustomAttributes A>
|
||||
bool hasCustomAttribute(const clang::Decl* D) {
|
||||
template <CustomAttributes A> bool hasCustomAttribute(const clang::Decl *D) {
|
||||
return false;
|
||||
}
|
||||
|
||||
extern CustomAttributesSet GetAttributes(const clang::Decl* D);
|
||||
extern CustomAttributesSet GetAttributes(const clang::Decl *D);
|
||||
|
||||
#define ATTR(name) \
|
||||
template<> \
|
||||
inline bool hasCustomAttribute<name>(const clang::Decl* D) { \
|
||||
return GetAttributes(D).has_ ## name; \
|
||||
#define ATTR(name) \
|
||||
template <> inline bool hasCustomAttribute<name>(const clang::Decl *D) { \
|
||||
return GetAttributes(D).has_##name; \
|
||||
}
|
||||
#include "CustomAttributes.inc"
|
||||
#undef ATTR
|
||||
|
||||
extern bool hasCustomAttribute(const clang::Decl* D, CustomAttributes A);
|
||||
extern bool hasCustomAttribute(const clang::Decl *D, CustomAttributes A);
|
||||
|
||||
#endif /* CustomAttributes_h__ */
|
||||
|
|
|
@ -224,18 +224,17 @@ AST_MATCHER_P(Expr, ignoreTrivials, internal::Matcher<Expr>, InnerMatcher) {
|
|||
return InnerMatcher.matches(*IgnoreTrivials(&Node), Finder, Builder);
|
||||
}
|
||||
|
||||
// Takes two matchers: the first one is a condition; the second is a matcher to be
|
||||
// applied once we are done unwrapping trivials. While the condition does not match
|
||||
// and we're looking at a trivial, will keep unwrapping the trivial and trying again.
|
||||
// Once the condition matches, we will go ahead and unwrap all trivials and apply the
|
||||
// inner matcher to the result.
|
||||
// Takes two matchers: the first one is a condition; the second is a matcher to
|
||||
// be applied once we are done unwrapping trivials. While the condition does
|
||||
// not match and we're looking at a trivial, will keep unwrapping the trivial
|
||||
// and trying again. Once the condition matches, we will go ahead and unwrap all
|
||||
// trivials and apply the inner matcher to the result.
|
||||
//
|
||||
// The expected use here is if we want to condition a match on some typecheck but
|
||||
// apply the match to only non-trivials, because there are trivials (e.g. casts) that
|
||||
// can change types.
|
||||
AST_MATCHER_P2(Expr, ignoreTrivialsConditional,
|
||||
internal::Matcher<Expr>, Condition,
|
||||
internal::Matcher<Expr>, InnerMatcher) {
|
||||
// The expected use here is if we want to condition a match on some typecheck
|
||||
// but apply the match to only non-trivials, because there are trivials (e.g.
|
||||
// casts) that can change types.
|
||||
AST_MATCHER_P2(Expr, ignoreTrivialsConditional, internal::Matcher<Expr>,
|
||||
Condition, internal::Matcher<Expr>, InnerMatcher) {
|
||||
const Expr *node = &Node;
|
||||
while (true) {
|
||||
if (Condition.matches(*node, Finder, Builder)) {
|
||||
|
@ -318,7 +317,8 @@ AST_MATCHER(QualType, isSmartPtrToRefCounted) {
|
|||
}
|
||||
|
||||
AST_MATCHER(ClassTemplateSpecializationDecl, isSmartPtrToRefCountedDecl) {
|
||||
auto *D = dyn_cast_or_null<CXXRecordDecl>(Node.getSpecializedTemplate()->getTemplatedDecl());
|
||||
auto *D = dyn_cast_or_null<CXXRecordDecl>(
|
||||
Node.getSpecializedTemplate()->getTemplatedDecl());
|
||||
if (!D) {
|
||||
return false;
|
||||
}
|
||||
|
@ -328,7 +328,6 @@ AST_MATCHER(ClassTemplateSpecializationDecl, isSmartPtrToRefCountedDecl) {
|
|||
return D && hasCustomAttribute<moz_is_smartptr_to_refcounted>(D);
|
||||
}
|
||||
|
||||
|
||||
AST_MATCHER(CXXRecordDecl, hasBaseClasses) {
|
||||
const CXXRecordDecl *Decl = Node.getCanonicalDecl();
|
||||
|
||||
|
@ -348,7 +347,8 @@ AST_MATCHER(CXXMethodDecl, isNonVirtual) {
|
|||
|
||||
AST_MATCHER(FunctionDecl, isMozMustReturnFromCaller) {
|
||||
const FunctionDecl *Decl = Node.getCanonicalDecl();
|
||||
return Decl && hasCustomAttribute<moz_must_return_from_caller_if_this_is_arg>(Decl);
|
||||
return Decl &&
|
||||
hasCustomAttribute<moz_must_return_from_caller_if_this_is_arg>(Decl);
|
||||
}
|
||||
|
||||
/// This matcher will select default args which have nullptr as the value.
|
||||
|
|
|
@ -42,35 +42,35 @@ void DanglingOnTemporaryChecker::registerMatchers(MatchFinder *AstMatcher) {
|
|||
// Main checker //
|
||||
//////////////////
|
||||
|
||||
auto hasParentCall = hasParent(expr(
|
||||
anyOf(cxxOperatorCallExpr(
|
||||
// If we're in a lamda, we may have an operator call expression
|
||||
// ancestor in the AST, but the temporary we're matching
|
||||
// against is not going to have the same lifetime as the
|
||||
// constructor call.
|
||||
unless(has(expr(ignoreTrivials(lambdaExpr())))),
|
||||
expr().bind("parentOperatorCallExpr")),
|
||||
callExpr(
|
||||
// If we're in a lamda, we may have a call expression
|
||||
// ancestor in the AST, but the temporary we're matching
|
||||
// against is not going to have the same lifetime as the
|
||||
// function call.
|
||||
unless(has(expr(ignoreTrivials(lambdaExpr())))),
|
||||
expr().bind("parentCallExpr")),
|
||||
objcMessageExpr(
|
||||
// If we're in a lamda, we may have an objc message expression
|
||||
// ancestor in the AST, but the temporary we're matching
|
||||
// against is not going to have the same lifetime as the
|
||||
// function call.
|
||||
unless(has(expr(ignoreTrivials(lambdaExpr())))),
|
||||
expr().bind("parentObjCMessageExpr")),
|
||||
cxxConstructExpr(
|
||||
// If we're in a lamda, we may have a construct expression
|
||||
// ancestor in the AST, but the temporary we're matching
|
||||
// against is not going to have the same lifetime as the
|
||||
// constructor call.
|
||||
unless(has(expr(ignoreTrivials(lambdaExpr())))),
|
||||
expr().bind("parentConstructExpr")))));
|
||||
auto hasParentCall = hasParent(
|
||||
expr(anyOf(cxxOperatorCallExpr(
|
||||
// If we're in a lamda, we may have an operator call
|
||||
// expression ancestor in the AST, but the temporary we're
|
||||
// matching against is not going to have the same lifetime
|
||||
// as the constructor call.
|
||||
unless(has(expr(ignoreTrivials(lambdaExpr())))),
|
||||
expr().bind("parentOperatorCallExpr")),
|
||||
callExpr(
|
||||
// If we're in a lamda, we may have a call expression
|
||||
// ancestor in the AST, but the temporary we're matching
|
||||
// against is not going to have the same lifetime as the
|
||||
// function call.
|
||||
unless(has(expr(ignoreTrivials(lambdaExpr())))),
|
||||
expr().bind("parentCallExpr")),
|
||||
objcMessageExpr(
|
||||
// If we're in a lamda, we may have an objc message
|
||||
// expression ancestor in the AST, but the temporary we're
|
||||
// matching against is not going to have the same lifetime
|
||||
// as the function call.
|
||||
unless(has(expr(ignoreTrivials(lambdaExpr())))),
|
||||
expr().bind("parentObjCMessageExpr")),
|
||||
cxxConstructExpr(
|
||||
// If we're in a lamda, we may have a construct expression
|
||||
// ancestor in the AST, but the temporary we're matching
|
||||
// against is not going to have the same lifetime as the
|
||||
// constructor call.
|
||||
unless(has(expr(ignoreTrivials(lambdaExpr())))),
|
||||
expr().bind("parentConstructExpr")))));
|
||||
|
||||
AstMatcher->addMatcher(
|
||||
// This is a matcher on a method call,
|
||||
|
|
|
@ -14,7 +14,7 @@ public:
|
|||
ASTConsumerPtr makeASTConsumer() { return AstMatcher.newASTConsumer(); }
|
||||
|
||||
private:
|
||||
#define CHECK(cls, name) cls cls##_ { name };
|
||||
#define CHECK(cls, name) cls cls##_{name};
|
||||
#include "Checks.inc"
|
||||
#undef CHECK
|
||||
MatchFinder AstMatcher;
|
||||
|
|
|
@ -21,8 +21,7 @@ void ExplicitOperatorBoolChecker::check(
|
|||
Result.Nodes.getNodeAs<CXXConversionDecl>("node");
|
||||
const CXXRecordDecl *Clazz = Method->getParent();
|
||||
|
||||
if (!Method->isExplicit() &&
|
||||
!hasCustomAttribute<moz_implicit>(Method) &&
|
||||
if (!Method->isExplicit() && !hasCustomAttribute<moz_implicit>(Method) &&
|
||||
!ASTIsInSystemHeader(Method->getASTContext(), *Method) &&
|
||||
isInterestingDeclForImplicitConversion(Method)) {
|
||||
diag(Method->getBeginLoc(), "bad implicit conversion operator for %0",
|
||||
|
|
|
@ -9,10 +9,9 @@
|
|||
|
||||
class FopenUsageChecker : public BaseCheck {
|
||||
public:
|
||||
FopenUsageChecker(StringRef CheckName,
|
||||
ContextType *Context = nullptr)
|
||||
: BaseCheck(CheckName, Context) {}
|
||||
void registerMatchers(MatchFinder* AstMatcher) override;
|
||||
FopenUsageChecker(StringRef CheckName, ContextType *Context = nullptr)
|
||||
: BaseCheck(CheckName, Context) {}
|
||||
void registerMatchers(MatchFinder *AstMatcher) override;
|
||||
void check(const MatchFinder::MatchResult &Result) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
#include "CustomMatchers.h"
|
||||
|
||||
void KungFuDeathGripChecker::registerMatchers(MatchFinder *AstMatcher) {
|
||||
AstMatcher->addMatcher(varDecl(allOf(hasType(isRefPtr()),
|
||||
hasLocalStorage(),
|
||||
AstMatcher->addMatcher(varDecl(allOf(hasType(isRefPtr()), hasLocalStorage(),
|
||||
hasInitializer(anything())))
|
||||
.bind("decl"),
|
||||
this);
|
||||
|
|
|
@ -9,10 +9,10 @@ void MustReturnFromCallerChecker::registerMatchers(MatchFinder *AstMatcher) {
|
|||
// Look for a call to a MOZ_MUST_RETURN_FROM_CALLER member
|
||||
AstMatcher->addMatcher(
|
||||
cxxMemberCallExpr(
|
||||
on(declRefExpr(to(parmVarDecl()))),
|
||||
callee(functionDecl(isMozMustReturnFromCaller())),
|
||||
anyOf(hasAncestor(lambdaExpr().bind("containing-lambda")),
|
||||
hasAncestor(functionDecl().bind("containing-func"))))
|
||||
on(declRefExpr(to(parmVarDecl()))),
|
||||
callee(functionDecl(isMozMustReturnFromCaller())),
|
||||
anyOf(hasAncestor(lambdaExpr().bind("containing-lambda")),
|
||||
hasAncestor(functionDecl().bind("containing-func"))))
|
||||
.bind("call"),
|
||||
this);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
#include "NoUsingNamespaceMozillaJavaChecker.h"
|
||||
#include "CustomMatchers.h"
|
||||
|
||||
void NoUsingNamespaceMozillaJavaChecker::registerMatchers(MatchFinder *AstMatcher) {
|
||||
void NoUsingNamespaceMozillaJavaChecker::registerMatchers(
|
||||
MatchFinder *AstMatcher) {
|
||||
AstMatcher->addMatcher(
|
||||
usingDirectiveDecl(isUsingNamespaceMozillaJava()).bind("directive"),
|
||||
this);
|
||||
|
@ -17,9 +18,7 @@ void NoUsingNamespaceMozillaJavaChecker::check(
|
|||
Result.Nodes.getNodeAs<UsingDirectiveDecl>("directive");
|
||||
const NamespaceDecl *Namespace = Directive->getNominatedNamespace();
|
||||
|
||||
diag(Directive->getUsingLoc(),
|
||||
"using namespace %0 is forbidden",
|
||||
diag(Directive->getUsingLoc(), "using namespace %0 is forbidden",
|
||||
DiagnosticIDs::Error)
|
||||
<< Namespace->getQualifiedNameAsString();
|
||||
}
|
||||
|
||||
|
|
|
@ -10,11 +10,10 @@
|
|||
class NoUsingNamespaceMozillaJavaChecker : public BaseCheck {
|
||||
public:
|
||||
NoUsingNamespaceMozillaJavaChecker(StringRef CheckName,
|
||||
ContextType *Context = nullptr)
|
||||
ContextType *Context = nullptr)
|
||||
: BaseCheck(CheckName, Context) {}
|
||||
void registerMatchers(MatchFinder *AstMatcher) override;
|
||||
void check(const MatchFinder::MatchResult &Result) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -5,17 +5,18 @@
|
|||
#include "ParamTraitsEnumChecker.h"
|
||||
#include "CustomMatchers.h"
|
||||
|
||||
void ParamTraitsEnumChecker::registerMatchers(MatchFinder* AstMatcher) {
|
||||
void ParamTraitsEnumChecker::registerMatchers(MatchFinder *AstMatcher) {
|
||||
AstMatcher->addMatcher(
|
||||
classTemplateSpecializationDecl(hasName("ParamTraits")).bind("decl"), this);
|
||||
classTemplateSpecializationDecl(hasName("ParamTraits")).bind("decl"),
|
||||
this);
|
||||
}
|
||||
|
||||
void ParamTraitsEnumChecker::check(const MatchFinder::MatchResult &Result) {
|
||||
const ClassTemplateSpecializationDecl *Decl =
|
||||
Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("decl");
|
||||
Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("decl");
|
||||
|
||||
for (auto& Inner : Decl->decls()) {
|
||||
if (auto* Def = dyn_cast<TypedefDecl>(Inner)) {
|
||||
for (auto &Inner : Decl->decls()) {
|
||||
if (auto *Def = dyn_cast<TypedefDecl>(Inner)) {
|
||||
QualType UnderlyingType = Def->getUnderlyingType();
|
||||
QualType CanonicalType = UnderlyingType.getCanonicalType();
|
||||
|
||||
|
|
|
@ -9,10 +9,9 @@
|
|||
|
||||
class ParamTraitsEnumChecker : public BaseCheck {
|
||||
public:
|
||||
ParamTraitsEnumChecker(StringRef CheckName,
|
||||
ContextType *Context = nullptr)
|
||||
: BaseCheck(CheckName, Context) {}
|
||||
void registerMatchers(MatchFinder* AstMatcher) override;
|
||||
ParamTraitsEnumChecker(StringRef CheckName, ContextType *Context = nullptr)
|
||||
: BaseCheck(CheckName, Context) {}
|
||||
void registerMatchers(MatchFinder *AstMatcher) override;
|
||||
void check(const MatchFinder::MatchResult &Result) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -10,8 +10,9 @@ void ScopeChecker::registerMatchers(MatchFinder *AstMatcher) {
|
|||
AstMatcher->addMatcher(cxxNewExpr().bind("node"), this);
|
||||
AstMatcher->addMatcher(
|
||||
materializeTemporaryExpr(
|
||||
unless(hasDescendant(cxxConstructExpr(allowsTemporary())))
|
||||
).bind("node"), this);
|
||||
unless(hasDescendant(cxxConstructExpr(allowsTemporary()))))
|
||||
.bind("node"),
|
||||
this);
|
||||
AstMatcher->addMatcher(
|
||||
callExpr(callee(functionDecl(heapAllocator()))).bind("node"), this);
|
||||
}
|
||||
|
@ -39,8 +40,7 @@ void ScopeChecker::check(const MatchFinder::MatchResult &Result) {
|
|||
QualType T;
|
||||
bool IsStaticLocal = false;
|
||||
|
||||
if (const ParmVarDecl *D =
|
||||
Result.Nodes.getNodeAs<ParmVarDecl>("node")) {
|
||||
if (const ParmVarDecl *D = Result.Nodes.getNodeAs<ParmVarDecl>("node")) {
|
||||
if (D->hasUnparsedDefaultArg() || D->hasUninstantiatedDefaultArg()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
#include "CustomMatchers.h"
|
||||
|
||||
void TrivialDtorChecker::registerMatchers(MatchFinder *AstMatcher) {
|
||||
AstMatcher->addMatcher(cxxRecordDecl(hasTrivialDtor()).bind("node"),
|
||||
this);
|
||||
AstMatcher->addMatcher(cxxRecordDecl(hasTrivialDtor()).bind("node"), this);
|
||||
}
|
||||
|
||||
void TrivialDtorChecker::check(const MatchFinder::MatchResult &Result) {
|
||||
|
|
|
@ -293,37 +293,37 @@ inline bool typeIsRefPtr(QualType Q) {
|
|||
// some AST trees. To get around this, we define our own implementation of
|
||||
// IgnoreTrivials.
|
||||
inline const Stmt *MaybeSkipOneTrivial(const Stmt *s) {
|
||||
if (!s) {
|
||||
return nullptr;
|
||||
}
|
||||
if (auto *ewc = dyn_cast<ExprWithCleanups>(s)) {
|
||||
return ewc->getSubExpr();
|
||||
}
|
||||
if (auto *mte = dyn_cast<MaterializeTemporaryExpr>(s)) {
|
||||
// With clang 10 and up `getTemporary` has been replaced with the more
|
||||
// versatile `getSubExpr`.
|
||||
if (!s) {
|
||||
return nullptr;
|
||||
}
|
||||
if (auto *ewc = dyn_cast<ExprWithCleanups>(s)) {
|
||||
return ewc->getSubExpr();
|
||||
}
|
||||
if (auto *mte = dyn_cast<MaterializeTemporaryExpr>(s)) {
|
||||
// With clang 10 and up `getTemporary` has been replaced with the more
|
||||
// versatile `getSubExpr`.
|
||||
#if CLANG_VERSION_FULL >= 1000
|
||||
return mte->getSubExpr();
|
||||
return mte->getSubExpr();
|
||||
#else
|
||||
return mte->GetTemporaryExpr();
|
||||
return mte->GetTemporaryExpr();
|
||||
#endif
|
||||
}
|
||||
if (auto *bte = dyn_cast<CXXBindTemporaryExpr>(s)) {
|
||||
return bte->getSubExpr();
|
||||
}
|
||||
if (auto *ce = dyn_cast<CastExpr>(s)) {
|
||||
s = ce->getSubExpr();
|
||||
}
|
||||
if (auto *pe = dyn_cast<ParenExpr>(s)) {
|
||||
s = pe->getSubExpr();
|
||||
}
|
||||
// Not a trivial.
|
||||
return s;
|
||||
}
|
||||
if (auto *bte = dyn_cast<CXXBindTemporaryExpr>(s)) {
|
||||
return bte->getSubExpr();
|
||||
}
|
||||
if (auto *ce = dyn_cast<CastExpr>(s)) {
|
||||
s = ce->getSubExpr();
|
||||
}
|
||||
if (auto *pe = dyn_cast<ParenExpr>(s)) {
|
||||
s = pe->getSubExpr();
|
||||
}
|
||||
// Not a trivial.
|
||||
return s;
|
||||
}
|
||||
|
||||
inline const Stmt *IgnoreTrivials(const Stmt *s) {
|
||||
while (true) {
|
||||
const Stmt* newS = MaybeSkipOneTrivial(s);
|
||||
const Stmt *newS = MaybeSkipOneTrivial(s);
|
||||
if (newS == s) {
|
||||
return newS;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче