diff --git a/clang-tools-extra/clang-doc/Generators.cpp b/clang-tools-extra/clang-doc/Generators.cpp index ec7133466f2e9f..3b7dcf93411af5 100644 --- a/clang-tools-extra/clang-doc/Generators.cpp +++ b/clang-tools-extra/clang-doc/Generators.cpp @@ -27,20 +27,6 @@ findGeneratorByName(llvm::StringRef Format) { // Enum conversion -std::string getAccess(AccessSpecifier AS) { - switch (AS) { - case AccessSpecifier::AS_public: - return "public"; - case AccessSpecifier::AS_protected: - return "protected"; - case AccessSpecifier::AS_private: - return "private"; - case AccessSpecifier::AS_none: - return {}; - } - llvm_unreachable("Unknown AccessSpecifier"); -} - std::string getTagType(TagTypeKind AS) { switch (AS) { case TagTypeKind::TTK_Class: diff --git a/clang-tools-extra/clang-doc/Generators.h b/clang-tools-extra/clang-doc/Generators.h index 799d503b102311..89c6b34c43844f 100644 --- a/clang-tools-extra/clang-doc/Generators.h +++ b/clang-tools-extra/clang-doc/Generators.h @@ -42,8 +42,6 @@ typedef llvm::Registry GeneratorRegistry; llvm::Expected> findGeneratorByName(llvm::StringRef Format); -std::string getAccess(AccessSpecifier AS); - std::string getTagType(TagTypeKind AS); } // namespace doc diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp index dc569e2a482c7a..49ff36a02be7f8 100644 --- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp +++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp @@ -402,7 +402,7 @@ genRecordMembersBlock(const llvm::SmallVector &Members, Out.emplace_back(std::make_unique(HTMLTag::TAG_UL)); auto &ULBody = Out.back(); for (const auto &M : Members) { - std::string Access = getAccess(M.Access); + std::string Access = getAccessSpelling(M.Access).str(); if (Access != "") Access = Access + " "; auto LIBody = std::make_unique(HTMLTag::TAG_LI); @@ -679,7 +679,7 @@ genHTML(const FunctionInfo &I, const ClangDocContext &CDCtx, Out.emplace_back(std::make_unique(HTMLTag::TAG_P)); auto &FunctionHeader = Out.back(); - std::string Access = getAccess(I.Access); + std::string Access = getAccessSpelling(I.Access).str(); if (Access != "") FunctionHeader->Children.emplace_back( std::make_unique(Access + " ")); diff --git a/clang-tools-extra/clang-doc/MDGenerator.cpp b/clang-tools-extra/clang-doc/MDGenerator.cpp index 9ad71e435a70ca..58c2de96b298cc 100644 --- a/clang-tools-extra/clang-doc/MDGenerator.cpp +++ b/clang-tools-extra/clang-doc/MDGenerator.cpp @@ -157,7 +157,7 @@ static void genMarkdown(const ClangDocContext &CDCtx, const FunctionInfo &I, First = false; } writeHeader(I.Name, 3, OS); - std::string Access = getAccess(I.Access); + std::string Access = getAccessSpelling(I.Access).str(); if (Access != "") writeLine(genItalic(Access + " " + I.ReturnType.Type.Name + " " + I.Name + "(" + Stream.str() + ")"), @@ -250,7 +250,7 @@ static void genMarkdown(const ClangDocContext &CDCtx, const RecordInfo &I, if (!I.Members.empty()) { writeHeader("Members", 2, OS); for (const auto &Member : I.Members) { - std::string Access = getAccess(Member.Access); + std::string Access = getAccessSpelling(Member.Access).str(); if (Access != "") writeLine(Access + " " + Member.Type.Name + " " + Member.Name, OS); else diff --git a/clang-tools-extra/clang-query/Query.cpp b/clang-tools-extra/clang-query/Query.cpp index 8eafc5eed7507e..2fc7af6a56e14d 100644 --- a/clang-tools-extra/clang-query/Query.cpp +++ b/clang-tools-extra/clang-query/Query.cpp @@ -43,6 +43,15 @@ bool HelpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { "Set whether to bind the root matcher to \"root\".\n" " set print-matcher (true|false) " "Set whether to print the current matcher,\n" + " set traversal " + "Set traversal kind of clang-query session. Available kinds are:\n" + " AsIs " + "Print and match the AST as clang sees it.\n" + " IgnoreImplicitCastsAndParentheses " + "Omit implicit casts and parens in matching and dumping.\n" + " IgnoreUnlessSpelledInSource " + "Omit AST nodes unless spelled in the source. This mode is the " + "default.\n" " set output " "Set whether to output only content.\n" " enable output " @@ -98,6 +107,8 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { OS << "Not a valid top-level matcher.\n"; return false; } + + AST->getASTContext().getParentMapContext().setTraversalKind(QS.TK); Finder.matchAST(AST->getASTContext()); if (QS.PrintMatcher) { @@ -148,6 +159,7 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { const SourceManager &SM = Ctx.getSourceManager(); ASTDumper Dumper(OS, &Ctx.getCommentCommandTraits(), &SM, SM.getDiagnostics().getShowColors(), Ctx.getPrintingPolicy()); + Dumper.SetTraversalKind(QS.TK); Dumper.Visit(BI->second); OS << "\n"; } diff --git a/clang-tools-extra/clang-query/Query.h b/clang-tools-extra/clang-query/Query.h index 78bcbc79cdf872..223644fe2e515b 100644 --- a/clang-tools-extra/clang-query/Query.h +++ b/clang-tools-extra/clang-query/Query.h @@ -28,6 +28,7 @@ enum QueryKind { QK_Match, QK_SetBool, QK_SetOutputKind, + QK_SetTraversalKind, QK_EnableOutputKind, QK_DisableOutputKind, QK_Quit @@ -119,6 +120,10 @@ template <> struct SetQueryKind { static const QueryKind value = QK_SetOutputKind; }; +template <> struct SetQueryKind { + static const QueryKind value = QK_SetTraversalKind; +}; + /// Query for "set VAR VALUE". template struct SetQuery : Query { SetQuery(T QuerySession::*Var, T Value) diff --git a/clang-tools-extra/clang-query/QueryParser.cpp b/clang-tools-extra/clang-query/QueryParser.cpp index ecc189a7db2f5d..2f1965e77ab4b4 100644 --- a/clang-tools-extra/clang-query/QueryParser.cpp +++ b/clang-tools-extra/clang-query/QueryParser.cpp @@ -128,6 +128,24 @@ template QueryRef QueryParser::parseSetOutputKind() { llvm_unreachable("Invalid output kind"); } +QueryRef QueryParser::parseSetTraversalKind( + ast_type_traits::TraversalKind QuerySession::*Var) { + StringRef ValStr; + unsigned Value = + LexOrCompleteWord(this, ValStr) + .Case("AsIs", ast_type_traits::TK_AsIs) + .Case("IgnoreImplicitCastsAndParentheses", + ast_type_traits::TK_IgnoreImplicitCastsAndParentheses) + .Case("IgnoreUnlessSpelledInSource", + ast_type_traits::TK_IgnoreUnlessSpelledInSource) + .Default(~0u); + if (Value == ~0u) { + return new InvalidQuery("expected traversal kind, got '" + ValStr + "'"); + } + return new SetQuery( + Var, static_cast(Value)); +} + QueryRef QueryParser::endQuery(QueryRef Q) { StringRef Extra = Line; StringRef ExtraTrimmed = Extra.drop_while( @@ -171,7 +189,8 @@ enum ParsedQueryVariable { PQV_Invalid, PQV_Output, PQV_BindRoot, - PQV_PrintMatcher + PQV_PrintMatcher, + PQV_Traversal }; QueryRef makeInvalidQueryFromDiagnostics(const Diagnostics &Diag) { @@ -272,6 +291,7 @@ QueryRef QueryParser::doParse() { .Case("output", PQV_Output) .Case("bind-root", PQV_BindRoot) .Case("print-matcher", PQV_PrintMatcher) + .Case("traversal", PQV_Traversal) .Default(PQV_Invalid); if (VarStr.empty()) return new InvalidQuery("expected variable name"); @@ -289,6 +309,9 @@ QueryRef QueryParser::doParse() { case PQV_PrintMatcher: Q = parseSetBool(&QuerySession::PrintMatcher); break; + case PQV_Traversal: + Q = parseSetTraversalKind(&QuerySession::TK); + break; case PQV_Invalid: llvm_unreachable("Invalid query kind"); } diff --git a/clang-tools-extra/clang-query/QueryParser.h b/clang-tools-extra/clang-query/QueryParser.h index 12664777ee447f..68f420dc0994ef 100644 --- a/clang-tools-extra/clang-query/QueryParser.h +++ b/clang-tools-extra/clang-query/QueryParser.h @@ -43,6 +43,8 @@ class QueryParser { template struct LexOrCompleteWord; QueryRef parseSetBool(bool QuerySession::*Var); + QueryRef + parseSetTraversalKind(ast_type_traits::TraversalKind QuerySession::*Var); template QueryRef parseSetOutputKind(); QueryRef completeMatcherExpression(); diff --git a/clang-tools-extra/clang-query/QuerySession.h b/clang-tools-extra/clang-query/QuerySession.h index 0f3bc1aa64641a..1660e4039f613b 100644 --- a/clang-tools-extra/clang-query/QuerySession.h +++ b/clang-tools-extra/clang-query/QuerySession.h @@ -9,6 +9,7 @@ #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_SESSION_H #define LLVM_CLANG_TOOLS_EXTRA_CLANG_QUERY_QUERY_SESSION_H +#include "clang/AST/ASTTypeTraits.h" #include "clang/ASTMatchers/Dynamic/VariantValue.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringMap.h" @@ -25,7 +26,7 @@ class QuerySession { QuerySession(llvm::ArrayRef> ASTs) : ASTs(ASTs), PrintOutput(false), DiagOutput(true), DetailedASTOutput(false), BindRoot(true), PrintMatcher(false), - Terminate(false) {} + Terminate(false), TK(ast_type_traits::TK_IgnoreUnlessSpelledInSource) {} llvm::ArrayRef> ASTs; @@ -36,6 +37,8 @@ class QuerySession { bool BindRoot; bool PrintMatcher; bool Terminate; + + ast_type_traits::TraversalKind TK; llvm::StringMap NamedValues; }; diff --git a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp index c17a43c73f9510..d179e6cb7c75b1 100644 --- a/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp +++ b/clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp @@ -104,9 +104,11 @@ findMembersUsedInInitExpr(const CXXCtorInitializer *Initializer, // for those accesses Sema::PerformObjectMemberConversion always inserts an // UncheckedDerivedToBase ImplicitCastExpr between the this expr and the // object expression - auto FoundExprs = - match(findAll(memberExpr(hasObjectExpression(cxxThisExpr())).bind("ME")), - *Initializer->getInit(), Context); + auto FoundExprs = match( + traverse( + TK_AsIs, + findAll(memberExpr(hasObjectExpression(cxxThisExpr())).bind("ME"))), + *Initializer->getInit(), Context); for (BoundNodes &BN : FoundExprs) if (auto *MemExpr = BN.getNodeAs("ME")) if (auto *FD = dyn_cast(MemExpr->getMemberDecl())) diff --git a/clang-tools-extra/clang-tidy/abseil/DurationDivisionCheck.cpp b/clang-tools-extra/clang-tidy/abseil/DurationDivisionCheck.cpp index 7055ff57fdcb7d..01e01469acee85 100644 --- a/clang-tools-extra/clang-tidy/abseil/DurationDivisionCheck.cpp +++ b/clang-tools-extra/clang-tidy/abseil/DurationDivisionCheck.cpp @@ -20,16 +20,17 @@ void DurationDivisionCheck::registerMatchers(MatchFinder *finder) { const auto DurationExpr = expr(hasType(cxxRecordDecl(hasName("::absl::Duration")))); finder->addMatcher( - implicitCastExpr( - hasSourceExpression(ignoringParenCasts( - cxxOperatorCallExpr(hasOverloadedOperatorName("/"), - hasArgument(0, DurationExpr), - hasArgument(1, DurationExpr)) - .bind("OpCall"))), - hasImplicitDestinationType(qualType(unless(isInteger()))), - unless(hasParent(cxxStaticCastExpr())), - unless(hasParent(cStyleCastExpr())), - unless(isInTemplateInstantiation())), + traverse(ast_type_traits::TK_AsIs, + implicitCastExpr( + hasSourceExpression(ignoringParenCasts( + cxxOperatorCallExpr(hasOverloadedOperatorName("/"), + hasArgument(0, DurationExpr), + hasArgument(1, DurationExpr)) + .bind("OpCall"))), + hasImplicitDestinationType(qualType(unless(isInteger()))), + unless(hasParent(cxxStaticCastExpr())), + unless(hasParent(cStyleCastExpr())), + unless(isInTemplateInstantiation()))), this); } diff --git a/clang-tools-extra/clang-tidy/abseil/FasterStrsplitDelimiterCheck.cpp b/clang-tools-extra/clang-tidy/abseil/FasterStrsplitDelimiterCheck.cpp index bca606a7bc3a21..ef260d9b1f6b8b 100644 --- a/clang-tools-extra/clang-tidy/abseil/FasterStrsplitDelimiterCheck.cpp +++ b/clang-tools-extra/clang-tidy/abseil/FasterStrsplitDelimiterCheck.cpp @@ -78,20 +78,23 @@ void FasterStrsplitDelimiterCheck::registerMatchers(MatchFinder *Finder) { // Find uses of absl::StrSplit(..., "x") and absl::StrSplit(..., // absl::ByAnyChar("x")) to transform them into absl::StrSplit(..., 'x'). - Finder->addMatcher(callExpr(callee(functionDecl(hasName("::absl::StrSplit"))), - hasArgument(1, anyOf(ByAnyCharArg, SingleChar)), - unless(isInTemplateInstantiation())) - .bind("StrSplit"), - this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, + callExpr(callee(functionDecl(hasName("::absl::StrSplit"))), + hasArgument(1, anyOf(ByAnyCharArg, SingleChar)), + unless(isInTemplateInstantiation())) + .bind("StrSplit")), + this); // Find uses of absl::MaxSplits("x", N) and // absl::MaxSplits(absl::ByAnyChar("x"), N) to transform them into // absl::MaxSplits('x', N). Finder->addMatcher( - callExpr( - callee(functionDecl(hasName("::absl::MaxSplits"))), - hasArgument(0, anyOf(ByAnyCharArg, ignoringParenCasts(SingleChar))), - unless(isInTemplateInstantiation())), + traverse(ast_type_traits::TK_AsIs, + callExpr(callee(functionDecl(hasName("::absl::MaxSplits"))), + hasArgument(0, anyOf(ByAnyCharArg, + ignoringParenCasts(SingleChar))), + unless(isInTemplateInstantiation()))), this); } diff --git a/clang-tools-extra/clang-tidy/abseil/RedundantStrcatCallsCheck.cpp b/clang-tools-extra/clang-tidy/abseil/RedundantStrcatCallsCheck.cpp index 982d59e2cbe6f6..e7d037743f6788 100644 --- a/clang-tools-extra/clang-tidy/abseil/RedundantStrcatCallsCheck.cpp +++ b/clang-tools-extra/clang-tidy/abseil/RedundantStrcatCallsCheck.cpp @@ -64,11 +64,12 @@ const clang::CallExpr* ProcessArgument(const Expr* Arg, static const auto* const Strcat = new auto(hasName("::absl::StrCat")); const auto IsStrcat = cxxBindTemporaryExpr( has(callExpr(callee(functionDecl(*Strcat))).bind("StrCat"))); - if (const auto* SubStrcatCall = selectFirst( + if (const auto *SubStrcatCall = selectFirst( "StrCat", - match(stmt(anyOf( - cxxConstructExpr(IsAlphanum, hasArgument(0, IsStrcat)), - IsStrcat)), + match(stmt(traverse(ast_type_traits::TK_AsIs, + anyOf(cxxConstructExpr(IsAlphanum, + hasArgument(0, IsStrcat)), + IsStrcat))), *Arg->IgnoreParenImpCasts(), *Result.Context))) { RemoveCallLeaveArgs(SubStrcatCall, CheckResult); return SubStrcatCall; diff --git a/clang-tools-extra/clang-tidy/abseil/StrCatAppendCheck.cpp b/clang-tools-extra/clang-tidy/abseil/StrCatAppendCheck.cpp index 0e8943f8545ec7..7aaf976a9c5886 100644 --- a/clang-tools-extra/clang-tidy/abseil/StrCatAppendCheck.cpp +++ b/clang-tools-extra/clang-tidy/abseil/StrCatAppendCheck.cpp @@ -58,14 +58,17 @@ void StrCatAppendCheck::registerMatchers(MatchFinder *Finder) { // StrCat on the RHS. The first argument of the StrCat call should be the same // as the LHS. Ignore calls from template instantiations. Finder->addMatcher( - cxxOperatorCallExpr( - unless(isInTemplateInstantiation()), hasOverloadedOperatorName("="), - hasArgument(0, declRefExpr(to(decl().bind("LHS")))), - hasArgument(1, IgnoringTemporaries( - callExpr(callee(StrCat), hasArgument(0, AlphaNum), - unless(HasAnotherReferenceToLhs)) - .bind("Call")))) - .bind("Op"), + traverse(ast_type_traits::TK_AsIs, + cxxOperatorCallExpr( + unless(isInTemplateInstantiation()), + hasOverloadedOperatorName("="), + hasArgument(0, declRefExpr(to(decl().bind("LHS")))), + hasArgument( + 1, IgnoringTemporaries( + callExpr(callee(StrCat), hasArgument(0, AlphaNum), + unless(HasAnotherReferenceToLhs)) + .bind("Call")))) + .bind("Op")), this); } diff --git a/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp b/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp index 2d0ffce733038b..a660cbdebda5a3 100644 --- a/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp +++ b/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp @@ -99,14 +99,17 @@ void UpgradeDurationConversionsCheck::registerMatchers(MatchFinder *Finder) { // `absl::Hours(x)` // where `x` is not of a built-in type. Finder->addMatcher( - implicitCastExpr( - anyOf(hasCastKind(CK_UserDefinedConversion), - has(implicitCastExpr(hasCastKind(CK_UserDefinedConversion)))), - hasParent(callExpr( - callee(functionDecl(DurationFactoryFunction(), - unless(hasParent(functionTemplateDecl())))), - hasArgument(0, expr().bind("arg"))))) - .bind("OuterExpr"), + traverse( + ast_type_traits::TK_AsIs, + implicitCastExpr(anyOf(hasCastKind(CK_UserDefinedConversion), + has(implicitCastExpr( + hasCastKind(CK_UserDefinedConversion)))), + hasParent(callExpr( + callee(functionDecl( + DurationFactoryFunction(), + unless(hasParent(functionTemplateDecl())))), + hasArgument(0, expr().bind("arg"))))) + .bind("OuterExpr")), this); } @@ -116,6 +119,8 @@ void UpgradeDurationConversionsCheck::check( "implicit conversion to 'int64_t' is deprecated in this context; use an " "explicit cast instead"; + TraversalKindScope RAII(*Result.Context, ast_type_traits::TK_AsIs); + const auto *ArgExpr = Result.Nodes.getNodeAs("arg"); SourceLocation Loc = ArgExpr->getBeginLoc(); diff --git a/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp index 4e3f76544dc8b9..5cb55639db7852 100644 --- a/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/AssertSideEffectCheck.cpp @@ -84,7 +84,8 @@ void AssertSideEffectCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { void AssertSideEffectCheck::registerMatchers(MatchFinder *Finder) { auto DescendantWithSideEffect = - hasDescendant(expr(hasSideEffect(CheckFunctionCalls))); + traverse(ast_type_traits::TK_AsIs, + hasDescendant(expr(hasSideEffect(CheckFunctionCalls)))); auto ConditionWithSideEffect = hasCondition(DescendantWithSideEffect); Finder->addMatcher( stmt( diff --git a/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp index b7f5b0d60e7786..b764bdbf7c4c55 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BoolPointerImplicitConversionCheck.cpp @@ -18,14 +18,16 @@ void BoolPointerImplicitConversionCheck::registerMatchers(MatchFinder *Finder) { // Look for ifs that have an implicit bool* to bool conversion in the // condition. Filter negations. Finder->addMatcher( - ifStmt(hasCondition(findAll(implicitCastExpr( - unless(hasParent(unaryOperator(hasOperatorName("!")))), - hasSourceExpression( - expr(hasType(pointerType(pointee(booleanType()))), - ignoringParenImpCasts(declRefExpr().bind("expr")))), - hasCastKind(CK_PointerToBoolean)))), - unless(isInTemplateInstantiation())) - .bind("if"), + traverse( + ast_type_traits::TK_AsIs, + ifStmt(hasCondition(findAll(implicitCastExpr( + unless(hasParent(unaryOperator(hasOperatorName("!")))), + hasSourceExpression(expr( + hasType(pointerType(pointee(booleanType()))), + ignoringParenImpCasts(declRefExpr().bind("expr")))), + hasCastKind(CK_PointerToBoolean)))), + unless(isInTemplateInstantiation())) + .bind("if")), this); } diff --git a/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.cpp index 74ad2e7535fc2c..5f771e49f808ca 100644 --- a/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/DanglingHandleCheck.cpp @@ -117,55 +117,63 @@ void DanglingHandleCheck::registerMatchersForVariables(MatchFinder *Finder) { // Find 'Handle foo = ReturnsAValue();' Finder->addMatcher( - varDecl( - hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(cxxRecordDecl(IsAHandle))))), - unless(parmVarDecl()), - hasInitializer(exprWithCleanups(has(ignoringParenImpCasts(handleFrom( + traverse(ast_type_traits::TK_AsIs, + varDecl(hasType(hasUnqualifiedDesugaredType(recordType( + hasDeclaration(cxxRecordDecl(IsAHandle))))), + unless(parmVarDecl()), + hasInitializer(exprWithCleanups( + has(ignoringParenImpCasts(handleFrom( IsAHandle, ConvertedHandle)))) - .bind("bad_stmt"))), + .bind("bad_stmt")))), this); // Find 'foo = ReturnsAValue(); // foo is Handle' Finder->addMatcher( - cxxOperatorCallExpr(callee(cxxMethodDecl(ofClass(IsAHandle))), - hasOverloadedOperatorName("="), - hasArgument(1, ConvertedHandle)) - .bind("bad_stmt"), + traverse(ast_type_traits::TK_AsIs, + cxxOperatorCallExpr(callee(cxxMethodDecl(ofClass(IsAHandle))), + hasOverloadedOperatorName("="), + hasArgument(1, ConvertedHandle)) + .bind("bad_stmt")), this); // Container insertions that will dangle. - Finder->addMatcher(makeContainerMatcher(IsAHandle).bind("bad_stmt"), this); + Finder->addMatcher(traverse(ast_type_traits::TK_AsIs, + makeContainerMatcher(IsAHandle).bind("bad_stmt")), + this); } void DanglingHandleCheck::registerMatchersForReturn(MatchFinder *Finder) { // Return a local. Finder->addMatcher( - returnStmt( - // The AST contains two constructor calls: - // 1. Value to Handle conversion. - // 2. Handle copy construction. - // We have to match both. - has(ignoringImplicit(handleFrom( - IsAHandle, - handleFrom(IsAHandle, - declRefExpr(to(varDecl( - // Is function scope ... - hasAutomaticStorageDuration(), - // ... and it is a local array or Value. - anyOf(hasType(arrayType()), - hasType(hasUnqualifiedDesugaredType( - recordType(hasDeclaration(recordDecl( - unless(IsAHandle)))))))))))))), - // Temporary fix for false positives inside lambdas. - unless(hasAncestor(lambdaExpr()))) - .bind("bad_stmt"), + traverse( + ast_type_traits::TK_AsIs, + returnStmt( + // The AST contains two constructor calls: + // 1. Value to Handle conversion. + // 2. Handle copy construction. + // We have to match both. + has(ignoringImplicit(handleFrom( + IsAHandle, + handleFrom(IsAHandle, + declRefExpr(to(varDecl( + // Is function scope ... + hasAutomaticStorageDuration(), + // ... and it is a local array or Value. + anyOf(hasType(arrayType()), + hasType(hasUnqualifiedDesugaredType( + recordType(hasDeclaration(recordDecl( + unless(IsAHandle)))))))))))))), + // Temporary fix for false positives inside lambdas. + unless(hasAncestor(lambdaExpr()))) + .bind("bad_stmt")), this); // Return a temporary. Finder->addMatcher( - returnStmt(has(exprWithCleanups(has(ignoringParenImpCasts(handleFrom( - IsAHandle, handleFromTemporaryValue(IsAHandle))))))) - .bind("bad_stmt"), + traverse( + ast_type_traits::TK_AsIs, + returnStmt(has(exprWithCleanups(has(ignoringParenImpCasts(handleFrom( + IsAHandle, handleFromTemporaryValue(IsAHandle))))))) + .bind("bad_stmt")), this); } diff --git a/clang-tools-extra/clang-tidy/bugprone/InaccurateEraseCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InaccurateEraseCheck.cpp index ef45f00d3e46ba..19e91b44b41afd 100644 --- a/clang-tools-extra/clang-tidy/bugprone/InaccurateEraseCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/InaccurateEraseCheck.cpp @@ -32,13 +32,15 @@ void InaccurateEraseCheck::registerMatchers(MatchFinder *Finder) { const auto DeclInStd = type(hasUnqualifiedDesugaredType( tagType(hasDeclaration(decl(isInStdNamespace()))))); Finder->addMatcher( - cxxMemberCallExpr( - on(anyOf(hasType(DeclInStd), hasType(pointsTo(DeclInStd)))), - callee(cxxMethodDecl(hasName("erase"))), argumentCountIs(1), - hasArgument(0, has(ignoringImplicit( - anyOf(EndCall, has(ignoringImplicit(EndCall)))))), - unless(isInTemplateInstantiation())) - .bind("erase"), + traverse( + ast_type_traits::TK_AsIs, + cxxMemberCallExpr( + on(anyOf(hasType(DeclInStd), hasType(pointsTo(DeclInStd)))), + callee(cxxMethodDecl(hasName("erase"))), argumentCountIs(1), + hasArgument(0, has(ignoringImplicit(anyOf( + EndCall, has(ignoringImplicit(EndCall)))))), + unless(isInTemplateInstantiation())) + .bind("erase")), this); } diff --git a/clang-tools-extra/clang-tidy/bugprone/IncorrectRoundingsCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/IncorrectRoundingsCheck.cpp index bc58e8e62b7af5..7b0682b31eb795 100644 --- a/clang-tools-extra/clang-tidy/bugprone/IncorrectRoundingsCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/IncorrectRoundingsCheck.cpp @@ -51,10 +51,11 @@ void IncorrectRoundingsCheck::registerMatchers(MatchFinder *MatchFinder) { // Find expressions of cast to int of the sum of a floating point expression // and 0.5. MatchFinder->addMatcher( - implicitCastExpr( - hasImplicitDestinationType(isInteger()), - ignoringParenCasts(binaryOperator(hasOperatorName("+"), OneSideHalf))) - .bind("CastExpr"), + traverse(ast_type_traits::TK_AsIs, + implicitCastExpr(hasImplicitDestinationType(isInteger()), + ignoringParenCasts(binaryOperator( + hasOperatorName("+"), OneSideHalf))) + .bind("CastExpr")), this); } diff --git a/clang-tools-extra/clang-tidy/bugprone/IntegerDivisionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/IntegerDivisionCheck.cpp index 82993cb313ce88..9214a7da272972 100644 --- a/clang-tools-extra/clang-tidy/bugprone/IntegerDivisionCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/IntegerDivisionCheck.cpp @@ -30,14 +30,16 @@ void IntegerDivisionCheck::registerMatchers(MatchFinder *Finder) { callExpr(IntType), explicitCastExpr(IntType), UnaryOperators); Finder->addMatcher( - binaryOperator( - hasOperatorName("/"), hasLHS(expr(IntType)), hasRHS(expr(IntType)), - hasAncestor( - castExpr(hasCastKind(CK_IntegralToFloating)).bind("FloatCast")), - unless(hasAncestor( - expr(Exceptions, - hasAncestor(castExpr(equalsBoundNode("FloatCast"))))))) - .bind("IntDiv"), + traverse(ast_type_traits::TK_AsIs, + binaryOperator( + hasOperatorName("/"), hasLHS(expr(IntType)), + hasRHS(expr(IntType)), + hasAncestor(castExpr(hasCastKind(CK_IntegralToFloating)) + .bind("FloatCast")), + unless(hasAncestor(expr( + Exceptions, + hasAncestor(castExpr(equalsBoundNode("FloatCast"))))))) + .bind("IntDiv")), this); } diff --git a/clang-tools-extra/clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.cpp index 10bbcb85420f65..ed2c17607169df 100644 --- a/clang-tools-extra/clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/MisplacedOperatorInStrlenInAllocCheck.cpp @@ -57,16 +57,22 @@ void MisplacedOperatorInStrlenInAllocCheck::registerMatchers( hasInitializer(ignoringParenImpCasts( declRefExpr(hasDeclaration(Alloc1Func))))); - Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc0Func, Alloc0FuncPtr))), - hasArgument(0, BadArg)) - .bind("Alloc"), - this); - Finder->addMatcher(callExpr(callee(decl(anyOf(Alloc1Func, Alloc1FuncPtr))), - hasArgument(1, BadArg)) - .bind("Alloc"), - this); Finder->addMatcher( - cxxNewExpr(isArray(), hasArraySize(BadArg)).bind("Alloc"), this); + traverse(ast_type_traits::TK_AsIs, + callExpr(callee(decl(anyOf(Alloc0Func, Alloc0FuncPtr))), + hasArgument(0, BadArg)) + .bind("Alloc")), + this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, + callExpr(callee(decl(anyOf(Alloc1Func, Alloc1FuncPtr))), + hasArgument(1, BadArg)) + .bind("Alloc")), + this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, + cxxNewExpr(isArray(), hasArraySize(BadArg)).bind("Alloc")), + this); } void MisplacedOperatorInStrlenInAllocCheck::check( diff --git a/clang-tools-extra/clang-tidy/bugprone/MisplacedWideningCastCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/MisplacedWideningCastCheck.cpp index 89fcda32a630fc..13f0e41a7a3e49 100644 --- a/clang-tools-extra/clang-tidy/bugprone/MisplacedWideningCastCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/MisplacedWideningCastCheck.cpp @@ -39,7 +39,9 @@ void MisplacedWideningCastCheck::registerMatchers(MatchFinder *Finder) { const auto ImplicitCast = implicitCastExpr(hasImplicitDestinationType(isInteger()), has(ignoringParenImpCasts(Calc))); - const auto Cast = expr(anyOf(ExplicitCast, ImplicitCast)).bind("Cast"); + const auto Cast = + traverse(ast_type_traits::TK_AsIs, + expr(anyOf(ExplicitCast, ImplicitCast)).bind("Cast")); Finder->addMatcher(varDecl(hasInitializer(Cast)), this); Finder->addMatcher(returnStmt(hasReturnValue(Cast)), this); diff --git a/clang-tools-extra/clang-tidy/bugprone/ParentVirtualCallCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ParentVirtualCallCheck.cpp index acc258a5bc5642..cfe556e5561077 100644 --- a/clang-tools-extra/clang-tidy/bugprone/ParentVirtualCallCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/ParentVirtualCallCheck.cpp @@ -83,14 +83,16 @@ static std::string getExprAsString(const clang::Expr &E, void ParentVirtualCallCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( - cxxMemberCallExpr( - callee(memberExpr(hasDescendant(implicitCastExpr( - hasImplicitDestinationType(pointsTo( - type(anything()).bind("castToType"))), - hasSourceExpression(cxxThisExpr(hasType( - type(anything()).bind("thisType"))))))) - .bind("member")), - callee(cxxMethodDecl(isVirtual()))), + traverse( + ast_type_traits::TK_AsIs, + cxxMemberCallExpr( + callee(memberExpr(hasDescendant(implicitCastExpr( + hasImplicitDestinationType(pointsTo( + type(anything()).bind("castToType"))), + hasSourceExpression(cxxThisExpr(hasType( + type(anything()).bind("thisType"))))))) + .bind("member")), + callee(cxxMethodDecl(isVirtual())))), this); } diff --git a/clang-tools-extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp index 3f72e5d516c501..555f8e11dff94b 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp @@ -70,8 +70,9 @@ BindableMatcher SignedCharMisuseCheck::charCastExpression( // We catch any type of casts to an integer. We need to have these cast // expressions explicitly to catch only those casts which are direct children // of the checked expressions. (e.g. assignment, declaration). - return expr(anyOf(ImplicitCastExpr, CStyleCastExpr, StaticCastExpr, - FunctionalCastExpr)); + return traverse(ast_type_traits::TK_AsIs, + expr(anyOf(ImplicitCastExpr, CStyleCastExpr, StaticCastExpr, + FunctionalCastExpr))); } void SignedCharMisuseCheck::registerMatchers(MatchFinder *Finder) { diff --git a/clang-tools-extra/clang-tidy/bugprone/StringConstructorCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/StringConstructorCheck.cpp index 1c47f17d8a6423..96d93a1d041379 100644 --- a/clang-tools-extra/clang-tidy/bugprone/StringConstructorCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/StringConstructorCheck.cpp @@ -100,10 +100,11 @@ void StringConstructorCheck::registerMatchers(MatchFinder *Finder) { // Check the literal string constructor with char pointer. // [i.e. string (const char* s);] Finder->addMatcher( + traverse(TK_AsIs, cxxConstructExpr(hasDeclaration(cxxMethodDecl(hasName("basic_string"))), hasArgument(0, expr().bind("from-ptr")), hasArgument(1, unless(hasType(isInteger())))) - .bind("constructor"), + .bind("constructor")), this); } diff --git a/clang-tools-extra/clang-tidy/bugprone/StringLiteralWithEmbeddedNulCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/StringLiteralWithEmbeddedNulCheck.cpp index 815062618a9789..b533db760d5eb5 100644 --- a/clang-tools-extra/clang-tidy/bugprone/StringLiteralWithEmbeddedNulCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/StringLiteralWithEmbeddedNulCheck.cpp @@ -49,8 +49,8 @@ void StringLiteralWithEmbeddedNulCheck::registerMatchers(MatchFinder *Finder) { // Detect passing a suspicious string literal to a string constructor. // example: std::string str = "abc\0def"; - Finder->addMatcher( - cxxConstructExpr(StringConstructorExpr, hasArgument(0, StrLitWithNul)), + Finder->addMatcher(traverse(TK_AsIs, + cxxConstructExpr(StringConstructorExpr, hasArgument(0, StrLitWithNul))), this); // Detect passing a suspicious string literal through an overloaded operator. diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousMissingCommaCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousMissingCommaCheck.cpp index b21fea185e2182..3de6dfed6356a3 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousMissingCommaCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousMissingCommaCheck.cpp @@ -22,6 +22,8 @@ bool isConcatenatedLiteralsOnPurpose(ASTContext *Ctx, const StringLiteral *Lit) { // String literals surrounded by parentheses are assumed to be on purpose. // i.e.: const char* Array[] = { ("a" "b" "c"), "d", [...] }; + + TraversalKindScope RAII(*Ctx, ast_type_traits::TK_AsIs); auto Parents = Ctx->getParents(*Lit); if (Parents.size() == 1 && Parents[0].get() != nullptr) return true; diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousStringCompareCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousStringCompareCheck.cpp index ee4850e9dce220..b4def0f9aa9dbe 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousStringCompareCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousStringCompareCheck.cpp @@ -135,9 +135,10 @@ void SuspiciousStringCompareCheck::registerMatchers(MatchFinder *Finder) { // Detect suspicious cast to an inconsistant type (i.e. not integer type). Finder->addMatcher( - implicitCastExpr(unless(hasType(isInteger())), - hasSourceExpression(StringCompareCallExpr)) - .bind("invalid-conversion"), + traverse(ast_type_traits::TK_AsIs, + implicitCastExpr(unless(hasType(isInteger())), + hasSourceExpression(StringCompareCallExpr)) + .bind("invalid-conversion")), this); // Detect suspicious operator with string compare function as operand. diff --git a/clang-tools-extra/clang-tidy/bugprone/TooSmallLoopVariableCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/TooSmallLoopVariableCheck.cpp index d8b11c9f1a2fad..be5a4697e94b1d 100644 --- a/clang-tools-extra/clang-tidy/bugprone/TooSmallLoopVariableCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/TooSmallLoopVariableCheck.cpp @@ -59,9 +59,10 @@ void TooSmallLoopVariableCheck::registerMatchers(MatchFinder *Finder) { // We need to catch only those comparisons which contain any integer cast. StatementMatcher LoopVarConversionMatcher = - implicitCastExpr(hasImplicitDestinationType(isInteger()), - has(ignoringParenImpCasts(LoopVarMatcher))) - .bind(LoopVarCastName); + traverse(ast_type_traits::TK_AsIs, + implicitCastExpr(hasImplicitDestinationType(isInteger()), + has(ignoringParenImpCasts(LoopVarMatcher))) + .bind(LoopVarCastName)); // We are interested in only those cases when the loop bound is a variable // value (not const, enum, etc.). diff --git a/clang-tools-extra/clang-tidy/bugprone/UndelegatedConstructorCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UndelegatedConstructorCheck.cpp index 1dd9568734ab07..839bc71fa59499 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UndelegatedConstructorCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UndelegatedConstructorCheck.cpp @@ -55,14 +55,16 @@ void UndelegatedConstructorCheck::registerMatchers(MatchFinder *Finder) { // instantiations to reduce the number of duplicated warnings. Finder->addMatcher( - compoundStmt( - hasParent( - cxxConstructorDecl(ofClass(cxxRecordDecl().bind("parent")))), - forEach(ignoringTemporaryExpr( - cxxConstructExpr(hasDeclaration(cxxConstructorDecl(ofClass( + traverse( + ast_type_traits::TK_AsIs, + compoundStmt(hasParent(cxxConstructorDecl( + ofClass(cxxRecordDecl().bind("parent")))), + forEach(ignoringTemporaryExpr( + cxxConstructExpr( + hasDeclaration(cxxConstructorDecl(ofClass( cxxRecordDecl(baseOfBoundNode("parent")))))) - .bind("construct"))), - unless(isInTemplateInstantiation())), + .bind("construct"))), + unless(isInTemplateInstantiation()))), this); } diff --git a/clang-tools-extra/clang-tidy/bugprone/UnhandledSelfAssignmentCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnhandledSelfAssignmentCheck.cpp index d91353e21fb108..1f1158f0479f87 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UnhandledSelfAssignmentCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UnhandledSelfAssignmentCheck.cpp @@ -52,8 +52,9 @@ void UnhandledSelfAssignmentCheck::registerMatchers(MatchFinder *Finder) { // In the non-template case, we can search for the copy constructor call. const auto HasNonTemplateSelfCopy = cxxMethodDecl( ofClass(cxxRecordDecl(unless(hasAncestor(classTemplateDecl())))), - hasDescendant(cxxConstructExpr(hasDeclaration(cxxConstructorDecl( - isCopyConstructor(), ofClass(equalsBoundNode("class"))))))); + traverse(ast_type_traits::TK_AsIs, + hasDescendant(cxxConstructExpr(hasDeclaration(cxxConstructorDecl( + isCopyConstructor(), ofClass(equalsBoundNode("class")))))))); // In the template case, we need to handle two separate cases: 1) a local // variable is created with the copy, 2) copy is created only as a temporary diff --git a/clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp index 409950834c40ab..34a489e324e4b7 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UnusedRaiiCheck.cpp @@ -31,13 +31,15 @@ void UnusedRaiiCheck::registerMatchers(MatchFinder *Finder) { cxxBindTemporaryExpr(unless(has(ignoringParenImpCasts(callExpr())))) .bind("temp"); Finder->addMatcher( - exprWithCleanups(unless(isInTemplateInstantiation()), - hasParent(compoundStmt().bind("compound")), - hasType(cxxRecordDecl(hasNonTrivialDestructor())), - anyOf(has(ignoringParenImpCasts(BindTemp)), - has(ignoringParenImpCasts(cxxFunctionalCastExpr( - has(ignoringParenImpCasts(BindTemp))))))) - .bind("expr"), + traverse(ast_type_traits::TK_AsIs, + exprWithCleanups( + unless(isInTemplateInstantiation()), + hasParent(compoundStmt().bind("compound")), + hasType(cxxRecordDecl(hasNonTrivialDestructor())), + anyOf(has(ignoringParenImpCasts(BindTemp)), + has(ignoringParenImpCasts(cxxFunctionalCastExpr( + has(ignoringParenImpCasts(BindTemp))))))) + .bind("expr")), this); } diff --git a/clang-tools-extra/clang-tidy/bugprone/UnusedReturnValueCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnusedReturnValueCheck.cpp index c3efb08d421371..d49fd63f005d4c 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UnusedReturnValueCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UnusedReturnValueCheck.cpp @@ -43,7 +43,90 @@ UnusedReturnValueCheck::UnusedReturnValueCheck(llvm::StringRef Name, "::std::unique;" "::std::unique_ptr::release;" "::std::basic_string::empty;" - "::std::vector::empty")) {} + "::std::vector::empty;" + "::std::back_inserter;" + "::std::distance;" + "::std::find;" + "::std::find_if;" + "::std::inserter;" + "::std::lower_bound;" + "::std::make_pair;" + "::std::map::count;" + "::std::map::find;" + "::std::map::lower_bound;" + "::std::multimap::equal_range;" + "::std::multimap::upper_bound;" + "::std::set::count;" + "::std::set::find;" + "::std::setfill;" + "::std::setprecision;" + "::std::setw;" + "::std::upper_bound;" + "::std::vector::at;" + // C standard library + "::bsearch;" + "::ferror;" + "::feof;" + "::isalnum;" + "::isalpha;" + "::isblank;" + "::iscntrl;" + "::isdigit;" + "::isgraph;" + "::islower;" + "::isprint;" + "::ispunct;" + "::isspace;" + "::isupper;" + "::iswalnum;" + "::iswprint;" + "::iswspace;" + "::isxdigit;" + "::memchr;" + "::memcmp;" + "::strcmp;" + "::strcoll;" + "::strncmp;" + "::strpbrk;" + "::strrchr;" + "::strspn;" + "::strstr;" + "::wcscmp;" + // POSIX + "::access;" + "::bind;" + "::connect;" + "::difftime;" + "::dlsym;" + "::fnmatch;" + "::getaddrinfo;" + "::getopt;" + "::htonl;" + "::htons;" + "::iconv_open;" + "::inet_addr;" + "::isascii;" + "::isatty;" + "::mmap;" + "::newlocale;" + "::openat;" + "::pathconf;" + "::pthread_equal;" + "::pthread_getspecific;" + "::pthread_mutex_trylock;" + "::readdir;" + "::readlink;" + "::recvmsg;" + "::regexec;" + "::scandir;" + "::semget;" + "::setjmp;" + "::shm_open;" + "::shmget;" + "::sigismember;" + "::strcasecmp;" + "::strsignal;" + "::ttyname")) {} void UnusedReturnValueCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "CheckedFunctions", CheckedFunctions); diff --git a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp index c9722a2f1b24d6..f65c02853a7369 100644 --- a/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/UseAfterMoveCheck.cpp @@ -275,7 +275,9 @@ void UseAfterMoveFinder::getDeclRefs( unless(inDecltypeOrTemplateArg())) .bind("declref"); - addDeclRefs(match(findAll(DeclRefMatcher), *S->getStmt(), *Context)); + addDeclRefs( + match(traverse(ast_type_traits::TK_AsIs, findAll(DeclRefMatcher)), + *S->getStmt(), *Context)); addDeclRefs(match(findAll(cxxOperatorCallExpr( hasAnyOverloadedOperatorName("*", "->", "[]"), hasArgument(0, DeclRefMatcher)) @@ -340,7 +342,7 @@ void UseAfterMoveFinder::getReinits( // Passing variable to a function as a non-const lvalue reference // (unless that function is std::move()). callExpr(forEachArgumentWithParam( - DeclRefMatcher, + traverse(ast_type_traits::TK_AsIs, DeclRefMatcher), unless(parmVarDecl(hasType( references(qualType(isConstQualified())))))), unless(callee(functionDecl(hasName("::std::move"))))))) @@ -403,19 +405,22 @@ void UseAfterMoveCheck::registerMatchers(MatchFinder *Finder) { .bind("call-move"); Finder->addMatcher( - // To find the Stmt that we assume performs the actual move, we look for - // the direct ancestor of the std::move() that isn't one of the node - // types ignored by ignoringParenImpCasts(). - stmt(forEach(expr(ignoringParenImpCasts(CallMoveMatcher))), - // Don't allow an InitListExpr to be the moving call. An InitListExpr - // has both a syntactic and a semantic form, and the parent-child - // relationships are different between the two. This could cause an - // InitListExpr to be analyzed as the moving call in addition to the - // Expr that we actually want, resulting in two diagnostics with - // different code locations for the same move. - unless(initListExpr()), - unless(expr(ignoringParenImpCasts(equalsBoundNode("call-move"))))) - .bind("moving-call"), + traverse( + ast_type_traits::TK_AsIs, + // To find the Stmt that we assume performs the actual move, we look + // for the direct ancestor of the std::move() that isn't one of the + // node types ignored by ignoringParenImpCasts(). + stmt( + forEach(expr(ignoringParenImpCasts(CallMoveMatcher))), + // Don't allow an InitListExpr to be the moving call. An + // InitListExpr has both a syntactic and a semantic form, and the + // parent-child relationships are different between the two. This + // could cause an InitListExpr to be analyzed as the moving call + // in addition to the Expr that we actually want, resulting in two + // diagnostics with different code locations for the same move. + unless(initListExpr()), + unless(expr(ignoringParenImpCasts(equalsBoundNode("call-move"))))) + .bind("moving-call")), this); } diff --git a/clang-tools-extra/clang-tidy/cert/MutatingCopyCheck.cpp b/clang-tools-extra/clang-tidy/cert/MutatingCopyCheck.cpp index 4de328f3249d65..678e7408bf4520 100644 --- a/clang-tools-extra/clang-tidy/cert/MutatingCopyCheck.cpp +++ b/clang-tools-extra/clang-tidy/cert/MutatingCopyCheck.cpp @@ -29,12 +29,13 @@ void MutatingCopyCheck::registerMatchers(MatchFinder *Finder) { allOf(unless(hasDescendant(expr(unless(MemberExprOrSourceObject)))), MemberExprOrSourceObject); - const auto IsSourceMutatingAssignment = + const auto IsSourceMutatingAssignment = traverse( + ast_type_traits::TK_AsIs, expr(anyOf(binaryOperator(isAssignmentOperator(), hasLHS(IsPartOfSource)) .bind(MutatingOperatorName), cxxOperatorCallExpr(isAssignmentOperator(), hasArgument(0, IsPartOfSource)) - .bind(MutatingOperatorName))); + .bind(MutatingOperatorName)))); const auto MemberExprOrSelf = anyOf(memberExpr(), cxxThisExpr()); diff --git a/clang-tools-extra/clang-tidy/cert/ProperlySeededRandomGeneratorCheck.cpp b/clang-tools-extra/clang-tidy/cert/ProperlySeededRandomGeneratorCheck.cpp index 3be83cf419b911..3fddbffeb1edf1 100644 --- a/clang-tools-extra/clang-tidy/cert/ProperlySeededRandomGeneratorCheck.cpp +++ b/clang-tools-extra/clang-tidy/cert/ProperlySeededRandomGeneratorCheck.cpp @@ -62,7 +62,9 @@ void ProperlySeededRandomGeneratorCheck::registerMatchers(MatchFinder *Finder) { // std::mt19937 engine(x); // ^ Finder->addMatcher( - cxxConstructExpr(RandomGeneratorEngineTypeMatcher).bind("ctor"), this); + traverse(ast_type_traits::TK_AsIs, + cxxConstructExpr(RandomGeneratorEngineTypeMatcher).bind("ctor")), + this); // srand(); // ^ diff --git a/clang-tools-extra/clang-tidy/cert/StaticObjectExceptionCheck.cpp b/clang-tools-extra/clang-tidy/cert/StaticObjectExceptionCheck.cpp index 233bd29cc8644c..9e255659bee7fc 100644 --- a/clang-tools-extra/clang-tidy/cert/StaticObjectExceptionCheck.cpp +++ b/clang-tools-extra/clang-tidy/cert/StaticObjectExceptionCheck.cpp @@ -21,7 +21,10 @@ void StaticObjectExceptionCheck::registerMatchers(MatchFinder *Finder) { // Match any static or thread_local variable declaration that has an // initializer that can throw. Finder->addMatcher( - varDecl(anyOf(hasThreadStorageDuration(), hasStaticStorageDuration()), + traverse( + ast_type_traits::TK_AsIs, + varDecl( + anyOf(hasThreadStorageDuration(), hasStaticStorageDuration()), unless(anyOf(isConstexpr(), hasType(cxxRecordDecl(isLambda())), hasAncestor(functionDecl()))), anyOf(hasDescendant(cxxConstructExpr(hasDeclaration( @@ -30,7 +33,7 @@ void StaticObjectExceptionCheck::registerMatchers(MatchFinder *Finder) { functionDecl(unless(isNoThrow())).bind("func")))), hasDescendant(callExpr(hasDeclaration( functionDecl(unless(isNoThrow())).bind("func")))))) - .bind("var"), + .bind("var")), this); } diff --git a/clang-tools-extra/clang-tidy/cert/ThrownExceptionTypeCheck.cpp b/clang-tools-extra/clang-tidy/cert/ThrownExceptionTypeCheck.cpp index ca44c002239f0e..6a6aab7eaf6fda 100644 --- a/clang-tools-extra/clang-tidy/cert/ThrownExceptionTypeCheck.cpp +++ b/clang-tools-extra/clang-tidy/cert/ThrownExceptionTypeCheck.cpp @@ -19,10 +19,12 @@ namespace cert { void ThrownExceptionTypeCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( - cxxThrowExpr(has(ignoringParenImpCasts( - cxxConstructExpr(hasDeclaration(cxxConstructorDecl( - isCopyConstructor(), unless(isNoThrow())))) - .bind("expr")))), + traverse( + ast_type_traits::TK_AsIs, + cxxThrowExpr(has(ignoringParenImpCasts( + cxxConstructExpr(hasDeclaration(cxxConstructorDecl( + isCopyConstructor(), unless(isNoThrow())))) + .bind("expr"))))), this); } diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.cpp index d9c91b230b1f51..fb19daf34172b2 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/InterfacesGlobalInitCheck.cpp @@ -27,11 +27,12 @@ void InterfacesGlobalInitCheck::registerMatchers(MatchFinder *Finder) { const auto ReferencesUndefinedGlobalVar = declRefExpr(hasDeclaration( varDecl(GlobalVarDecl, unless(isDefinition())).bind("referencee"))); - Finder->addMatcher( - varDecl(GlobalVarDecl, isDefinition(), - hasInitializer(expr(hasDescendant(ReferencesUndefinedGlobalVar)))) - .bind("var"), - this); + Finder->addMatcher(traverse(ast_type_traits::TK_AsIs, + varDecl(GlobalVarDecl, isDefinition(), + hasInitializer(expr(hasDescendant( + ReferencesUndefinedGlobalVar)))) + .bind("var")), + this); } void InterfacesGlobalInitCheck::check(const MatchFinder::MatchResult &Result) { diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp index 2f521ce6eefe94..2ae21a303ef7fc 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/NarrowingConversionsCheck.cpp @@ -39,12 +39,14 @@ void NarrowingConversionsCheck::registerMatchers(MatchFinder *Finder) { // i = 0.5; // void f(int); f(0.5); Finder->addMatcher( - implicitCastExpr(hasImplicitDestinationType(builtinType()), - hasSourceExpression(hasType(builtinType())), - unless(hasSourceExpression(IsCeilFloorCallExpr)), - unless(hasParent(castExpr())), - unless(isInTemplateInstantiation())) - .bind("cast"), + traverse( + ast_type_traits::TK_AsIs, + implicitCastExpr(hasImplicitDestinationType(builtinType()), + hasSourceExpression(hasType(builtinType())), + unless(hasSourceExpression(IsCeilFloorCallExpr)), + unless(hasParent(castExpr())), + unless(isInTemplateInstantiation())) + .bind("cast")), this); // Binary operators: diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp index 27ee0e48bb595e..79c1b6ccd6152b 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/OwningMemoryCheck.cpp @@ -69,10 +69,10 @@ void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) { // Find delete expressions that delete non-owners. Finder->addMatcher( - cxxDeleteExpr( - hasDescendant( - declRefExpr(unless(ConsideredOwner)).bind("deleted_variable"))) - .bind("delete_expr"), + traverse(ast_type_traits::TK_AsIs, + cxxDeleteExpr(hasDescendant(declRefExpr(unless(ConsideredOwner)) + .bind("deleted_variable"))) + .bind("delete_expr")), this); // Ignoring the implicit casts is vital because the legacy owners do not work @@ -83,23 +83,29 @@ void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) { // resources. This check assumes that all pointer arguments of a legacy // functions shall be 'gsl::owner<>'. Finder->addMatcher( - callExpr(callee(LegacyOwnerConsumers), - hasAnyArgument(expr(unless(ignoringImpCasts(ConsideredOwner)), - hasType(pointerType())))) - .bind("legacy_consumer"), + traverse(ast_type_traits::TK_AsIs, + callExpr(callee(LegacyOwnerConsumers), + hasAnyArgument( + expr(unless(ignoringImpCasts(ConsideredOwner)), + hasType(pointerType())))) + .bind("legacy_consumer")), this); // Matching assignment to owners, with the rhs not being an owner nor creating // one. - Finder->addMatcher(binaryOperator(isAssignmentOperator(), hasLHS(IsOwnerType), - hasRHS(unless(ConsideredOwner))) - .bind("owner_assignment"), - this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, + binaryOperator(isAssignmentOperator(), hasLHS(IsOwnerType), + hasRHS(unless(ConsideredOwner))) + .bind("owner_assignment")), + this); // Matching initialization of owners with non-owners, nor creating owners. Finder->addMatcher( - namedDecl(varDecl(hasInitializer(unless(ConsideredOwner)), IsOwnerType) - .bind("owner_initialization")), + traverse(ast_type_traits::TK_AsIs, + namedDecl( + varDecl(hasInitializer(unless(ConsideredOwner)), IsOwnerType) + .bind("owner_initialization"))), this); const auto HasConstructorInitializerForOwner = @@ -114,7 +120,9 @@ void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) { // Match class member initialization that expects owners, but does not get // them. - Finder->addMatcher(cxxRecordDecl(HasConstructorInitializerForOwner), this); + Finder->addMatcher(traverse(ast_type_traits::TK_AsIs, + cxxRecordDecl(HasConstructorInitializerForOwner)), + this); // Matching on assignment operations where the RHS is a newly created owner, // but the LHS is not an owner. @@ -127,11 +135,14 @@ void OwningMemoryCheck::registerMatchers(MatchFinder *Finder) { // Matching on initialization operations where the initial value is a newly // created owner, but the LHS is not an owner. Finder->addMatcher( - namedDecl(varDecl(eachOf(allOf(hasInitializer(CreatesOwner), - unless(IsOwnerType)), - allOf(hasInitializer(ConsideredOwner), - hasType(autoType().bind("deduced_type"))))) - .bind("bad_owner_creation_variable")), + traverse( + ast_type_traits::TK_AsIs, + namedDecl( + varDecl(eachOf(allOf(hasInitializer(CreatesOwner), + unless(IsOwnerType)), + allOf(hasInitializer(ConsideredOwner), + hasType(autoType().bind("deduced_type"))))) + .bind("bad_owner_creation_variable"))), this); // Match on all function calls that expect owners as arguments, but didn't diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp index cdea1375aba733..2b80c0ba25d688 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsArrayToPointerDecayCheck.cpp @@ -54,12 +54,13 @@ void ProBoundsArrayToPointerDecayCheck::registerMatchers(MatchFinder *Finder) { // 2) inside a range-for over an array // 3) if it converts a string literal to a pointer Finder->addMatcher( - implicitCastExpr( - unless(hasParent(arraySubscriptExpr())), - unless(hasParentIgnoringImpCasts(explicitCastExpr())), - unless(isInsideOfRangeBeginEndStmt()), - unless(hasSourceExpression(ignoringParens(stringLiteral())))) - .bind("cast"), + traverse(ast_type_traits::TK_AsIs, + implicitCastExpr( + unless(hasParent(arraySubscriptExpr())), + unless(hasParentIgnoringImpCasts(explicitCastExpr())), + unless(isInsideOfRangeBeginEndStmt()), + unless(hasSourceExpression(ignoringParens(stringLiteral())))) + .bind("cast")), this); } diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp index 6f0afe989d418f..62d752f299d35d 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/SlicingCheck.cpp @@ -63,7 +63,9 @@ void SlicingCheck::registerMatchers(MatchFinder *Finder) { unless(IsWithinDerivedCtor)); Finder->addMatcher( - expr(anyOf(SlicesObjectInAssignment, SlicesObjectInCtor)).bind("Call"), + traverse(ast_type_traits::TK_AsIs, + expr(anyOf(SlicesObjectInAssignment, SlicesObjectInCtor)) + .bind("Call")), this); } diff --git a/clang-tools-extra/clang-tidy/fuchsia/StaticallyConstructedObjectsCheck.cpp b/clang-tools-extra/clang-tidy/fuchsia/StaticallyConstructedObjectsCheck.cpp index ca2f85fc106cc1..b76c9f5fb6b608 100644 --- a/clang-tools-extra/clang-tidy/fuchsia/StaticallyConstructedObjectsCheck.cpp +++ b/clang-tools-extra/clang-tidy/fuchsia/StaticallyConstructedObjectsCheck.cpp @@ -28,17 +28,19 @@ void StaticallyConstructedObjectsCheck::registerMatchers(MatchFinder *Finder) { // Constructing global, non-trivial objects with static storage is // disallowed, unless the object is statically initialized with a constexpr // constructor or has no explicit constructor. - Finder->addMatcher(varDecl( - // Match global, statically stored objects... - isGlobalStatic(), - // ... that have C++ constructors... - hasDescendant(cxxConstructExpr(unless(allOf( - // ... unless it is constexpr ... - hasDeclaration(cxxConstructorDecl(isConstexpr())), - // ... and is statically initialized. - isConstantInitializer()))))) - .bind("decl"), - this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, + varDecl( + // Match global, statically stored objects... + isGlobalStatic(), + // ... that have C++ constructors... + hasDescendant(cxxConstructExpr(unless(allOf( + // ... unless it is constexpr ... + hasDeclaration(cxxConstructorDecl(isConstexpr())), + // ... and is statically initialized. + isConstantInitializer()))))) + .bind("decl")), + this); } void StaticallyConstructedObjectsCheck::check( diff --git a/clang-tools-extra/clang-tidy/llvm/PreferIsaOrDynCastInConditionalsCheck.cpp b/clang-tools-extra/clang-tidy/llvm/PreferIsaOrDynCastInConditionalsCheck.cpp index b9743e94fe3440..2ca976fd4bc954 100644 --- a/clang-tools-extra/clang-tidy/llvm/PreferIsaOrDynCastInConditionalsCheck.cpp +++ b/clang-tools-extra/clang-tidy/llvm/PreferIsaOrDynCastInConditionalsCheck.cpp @@ -52,15 +52,17 @@ void PreferIsaOrDynCastInConditionalsCheck::registerMatchers( .bind("rhs"); Finder->addMatcher( - stmt(anyOf(ifStmt(Any), whileStmt(Any), doStmt(Condition), - binaryOperator( - allOf(unless(isExpansionInFileMatching( - "llvm/include/llvm/Support/Casting.h")), - hasOperatorName("&&"), - hasLHS(implicitCastExpr().bind("lhs")), - hasRHS(anyOf(implicitCastExpr(has(CallExpression)), - CallExpression)))) - .bind("and"))), + traverse(ast_type_traits::TK_AsIs, + stmt(anyOf( + ifStmt(Any), whileStmt(Any), doStmt(Condition), + binaryOperator( + allOf(unless(isExpansionInFileMatching( + "llvm/include/llvm/Support/Casting.h")), + hasOperatorName("&&"), + hasLHS(implicitCastExpr().bind("lhs")), + hasRHS(anyOf(implicitCastExpr(has(CallExpression)), + CallExpression)))) + .bind("and")))), this); } diff --git a/clang-tools-extra/clang-tidy/llvm/PreferRegisterOverUnsignedCheck.cpp b/clang-tools-extra/clang-tidy/llvm/PreferRegisterOverUnsignedCheck.cpp index 3b2e9911d9d1de..006c8df1b07cf4 100644 --- a/clang-tools-extra/clang-tidy/llvm/PreferRegisterOverUnsignedCheck.cpp +++ b/clang-tools-extra/clang-tidy/llvm/PreferRegisterOverUnsignedCheck.cpp @@ -21,13 +21,15 @@ void PreferRegisterOverUnsignedCheck::registerMatchers(MatchFinder *Finder) { cxxRecordDecl(hasName("::llvm::Register")).bind("registerClassDecl")); Finder->addMatcher( - valueDecl(allOf( - hasType(qualType(isUnsignedInteger()).bind("varType")), - varDecl(hasInitializer(exprWithCleanups(has(implicitCastExpr(has( - cxxMemberCallExpr(allOf(on(RegisterClassMatch), - has(memberExpr(hasDeclaration( - cxxConversionDecl()))))))))))) - .bind("var"))), + traverse(ast_type_traits::TK_AsIs, + valueDecl(allOf( + hasType(qualType(isUnsignedInteger()).bind("varType")), + varDecl(hasInitializer(exprWithCleanups( + has(implicitCastExpr(has(cxxMemberCallExpr( + allOf(on(RegisterClassMatch), + has(memberExpr(hasDeclaration( + cxxConversionDecl()))))))))))) + .bind("var")))), this); } diff --git a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp index 4d54489e71b6a1..edb765b287f9c7 100644 --- a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp @@ -828,18 +828,20 @@ void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) { // Binary with equivalent operands, like (X != 2 && X != 2). Finder->addMatcher( - binaryOperator(anyOf(isComparisonOperator(), - hasAnyOperatorName("-", "/", "%", "|", "&", "^", - "&&", "||", "=")), - operandsAreEquivalent(), - // Filter noisy false positives. - unless(isInTemplateInstantiation()), - unless(binaryOperatorIsInMacro()), - unless(hasType(realFloatingPointType())), - unless(hasEitherOperand(hasType(realFloatingPointType()))), - unless(hasLHS(AnyLiteralExpr)), - unless(hasDescendant(BannedIntegerLiteral))) - .bind("binary"), + traverse(ast_type_traits::TK_AsIs, + binaryOperator( + anyOf(isComparisonOperator(), + hasAnyOperatorName("-", "/", "%", "|", "&", "^", "&&", + "||", "=")), + operandsAreEquivalent(), + // Filter noisy false positives. + unless(isInTemplateInstantiation()), + unless(binaryOperatorIsInMacro()), + unless(hasType(realFloatingPointType())), + unless(hasEitherOperand(hasType(realFloatingPointType()))), + unless(hasLHS(AnyLiteralExpr)), + unless(hasDescendant(BannedIntegerLiteral))) + .bind("binary")), this); // Logical or bitwise operator with equivalent nested operands, like (X && Y @@ -856,23 +858,27 @@ void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) { this); // Conditional (trenary) operator with equivalent operands, like (Y ? X : X). - Finder->addMatcher(conditionalOperator(expressionsAreEquivalent(), - // Filter noisy false positives. - unless(conditionalOperatorIsInMacro()), - unless(isInTemplateInstantiation())) - .bind("cond"), - this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, + conditionalOperator(expressionsAreEquivalent(), + // Filter noisy false positives. + unless(conditionalOperatorIsInMacro()), + unless(isInTemplateInstantiation())) + .bind("cond")), + this); // Overloaded operators with equivalent operands. - Finder->addMatcher(cxxOperatorCallExpr( - hasAnyOverloadedOperatorName( - "-", "/", "%", "|", "&", "^", "==", "!=", "<", - "<=", ">", ">=", "&&", "||", "="), - parametersAreEquivalent(), - // Filter noisy false positives. - unless(isMacro()), unless(isInTemplateInstantiation())) - .bind("call"), - this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, + cxxOperatorCallExpr( + hasAnyOverloadedOperatorName("-", "/", "%", "|", "&", "^", + "==", "!=", "<", "<=", ">", + ">=", "&&", "||", "="), + parametersAreEquivalent(), + // Filter noisy false positives. + unless(isMacro()), unless(isInTemplateInstantiation())) + .bind("call")), + this); // Overloaded operators with equivalent operands. Finder->addMatcher( @@ -886,30 +892,34 @@ void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) { // Match expressions like: !(1 | 2 | 3) Finder->addMatcher( - implicitCastExpr( - hasImplicitDestinationType(isInteger()), - has(unaryOperator( - hasOperatorName("!"), - hasUnaryOperand(ignoringParenImpCasts(binaryOperator( - hasAnyOperatorName("|", "&"), - hasLHS(anyOf(binaryOperator(hasAnyOperatorName("|", "&")), + traverse(ast_type_traits::TK_AsIs, + implicitCastExpr( + hasImplicitDestinationType(isInteger()), + has(unaryOperator( + hasOperatorName("!"), + hasUnaryOperand(ignoringParenImpCasts(binaryOperator( + hasAnyOperatorName("|", "&"), + hasLHS(anyOf( + binaryOperator(hasAnyOperatorName("|", "&")), integerLiteral())), - hasRHS(integerLiteral()))))) - .bind("logical-bitwise-confusion"))), + hasRHS(integerLiteral()))))) + .bind("logical-bitwise-confusion")))), this); - // Match expressions like: (X << 8) & 0xFF - Finder->addMatcher( + // Match expressions like: (X << 8) & 0xFF + Finder->addMatcher( + traverse( + ast_type_traits::TK_AsIs, binaryOperator( hasOperatorName("&"), hasOperands( ignoringParenImpCasts( binaryOperator(hasOperatorName("<<"), - hasRHS(ignoringParenImpCasts( + hasRHS(ignoringParenImpCasts( integerLiteral().bind("shift-const"))))), ignoringParenImpCasts(integerLiteral().bind("and-const")))) - .bind("left-right-shift-confusion"), - this); + .bind("left-right-shift-confusion")), + this); // Match common expressions and apply more checks to find redundant // sub-expressions. @@ -923,26 +933,32 @@ void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) { const auto SymRight = matchSymbolicExpr("rhs"); // Match expressions like: x 0xFF == 0xF00. - Finder->addMatcher(binaryOperator(isComparisonOperator(), - hasOperands(BinOpCstLeft, CstRight)) - .bind("binop-const-compare-to-const"), + Finder->addMatcher(traverse(ast_type_traits::TK_AsIs, + binaryOperator(isComparisonOperator(), + hasOperands(BinOpCstLeft, + CstRight)) + .bind("binop-const-compare-to-const")), this); // Match expressions like: x 0xFF == x. Finder->addMatcher( - binaryOperator(isComparisonOperator(), - anyOf(allOf(hasLHS(BinOpCstLeft), hasRHS(SymRight)), - allOf(hasLHS(SymRight), hasRHS(BinOpCstLeft)))) - .bind("binop-const-compare-to-sym"), + traverse( + ast_type_traits::TK_AsIs, + binaryOperator(isComparisonOperator(), + anyOf(allOf(hasLHS(BinOpCstLeft), hasRHS(SymRight)), + allOf(hasLHS(SymRight), hasRHS(BinOpCstLeft)))) + .bind("binop-const-compare-to-sym")), this); // Match expressions like: x 10 == x 12. - Finder->addMatcher(binaryOperator(isComparisonOperator(), - hasLHS(BinOpCstLeft), hasRHS(BinOpCstRight), - // Already reported as redundant. - unless(operandsAreEquivalent())) - .bind("binop-const-compare-to-binop-const"), - this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, + binaryOperator(isComparisonOperator(), hasLHS(BinOpCstLeft), + hasRHS(BinOpCstRight), + // Already reported as redundant. + unless(operandsAreEquivalent())) + .bind("binop-const-compare-to-binop-const")), + this); // Match relational expressions combined with logical operators and find // redundant sub-expressions. @@ -951,13 +967,14 @@ void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) { // Match expressions like: x < 2 && x > 2. const auto ComparisonLeft = matchRelationalIntegerConstantExpr("lhs"); const auto ComparisonRight = matchRelationalIntegerConstantExpr("rhs"); - Finder->addMatcher(binaryOperator(hasAnyOperatorName("||", "&&"), - hasLHS(ComparisonLeft), - hasRHS(ComparisonRight), - // Already reported as redundant. - unless(operandsAreEquivalent())) - .bind("comparisons-of-symbol-and-const"), - this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, + binaryOperator(hasAnyOperatorName("||", "&&"), + hasLHS(ComparisonLeft), hasRHS(ComparisonRight), + // Already reported as redundant. + unless(operandsAreEquivalent())) + .bind("comparisons-of-symbol-and-const")), + this); } void RedundantExpressionCheck::checkArithmeticExpr( diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp index 011da5e8840d8a..aa914ef7bbf52f 100644 --- a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp @@ -489,9 +489,12 @@ void LoopConvertCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { } void LoopConvertCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher(makeArrayLoopMatcher(), this); - Finder->addMatcher(makeIteratorLoopMatcher(), this); - Finder->addMatcher(makePseudoArrayLoopMatcher(), this); + Finder->addMatcher(traverse(ast_type_traits::TK_AsIs, makeArrayLoopMatcher()), + this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, makeIteratorLoopMatcher()), this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, makePseudoArrayLoopMatcher()), this); } /// Given the range of a single declaration, such as: @@ -897,6 +900,7 @@ void LoopConvertCheck::check(const MatchFinder::MatchResult &Result) { } // Find out which qualifiers we have to use in the loop range. + TraversalKindScope RAII(*Context, ast_type_traits::TK_AsIs); const UsageResult &Usages = Finder.getUsages(); determineRangeDescriptor(Context, Nodes, Loop, FixerKind, ContainerExpr, Usages, Descriptor); diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp index c49f7665d49023..e34fd7038bb869 100644 --- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp @@ -83,27 +83,29 @@ void MakeSmartPtrCheck::registerMatchers(ast_matchers::MatchFinder *Finder) { auto IsPlacement = hasAnyPlacementArg(anything()); Finder->addMatcher( - cxxBindTemporaryExpr(has(ignoringParenImpCasts( - cxxConstructExpr( - hasType(getSmartPointerTypeMatcher()), argumentCountIs(1), - hasArgument(0, - cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType( - equalsBoundNode(PointerType))))), - CanCallCtor, unless(IsPlacement)) - .bind(NewExpression)), - unless(isInTemplateInstantiation())) - .bind(ConstructorCall)))), + traverse( + ast_type_traits::TK_AsIs, + cxxBindTemporaryExpr(has(ignoringParenImpCasts( + cxxConstructExpr( + hasType(getSmartPointerTypeMatcher()), argumentCountIs(1), + hasArgument( + 0, cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType( + equalsBoundNode(PointerType))))), + CanCallCtor, unless(IsPlacement)) + .bind(NewExpression)), + unless(isInTemplateInstantiation())) + .bind(ConstructorCall))))), this); Finder->addMatcher( - cxxMemberCallExpr( - thisPointerType(getSmartPointerTypeMatcher()), - callee(cxxMethodDecl(hasName("reset"))), - hasArgument( - 0, - cxxNewExpr(CanCallCtor, unless(IsPlacement)).bind(NewExpression)), - unless(isInTemplateInstantiation())) - .bind(ResetCall), + traverse(ast_type_traits::TK_AsIs, + cxxMemberCallExpr( + thisPointerType(getSmartPointerTypeMatcher()), + callee(cxxMethodDecl(hasName("reset"))), + hasArgument(0, cxxNewExpr(CanCallCtor, unless(IsPlacement)) + .bind(NewExpression)), + unless(isInTemplateInstantiation())) + .bind(ResetCall)), this); } @@ -255,6 +257,8 @@ bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag, const CXXNewExpr *New, SourceManager &SM, ASTContext *Ctx) { auto SkipParensParents = [&](const Expr *E) { + TraversalKindScope RAII(*Ctx, ast_type_traits::TK_AsIs); + for (const Expr *OldE = nullptr; E != OldE;) { OldE = E; for (const auto &Node : Ctx->getParents(*E)) { diff --git a/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp b/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp index ae4837fe3893c1..633f3781f4d87e 100644 --- a/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/PassByValueCheck.cpp @@ -133,33 +133,36 @@ void PassByValueCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { void PassByValueCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( - cxxConstructorDecl( - forEachConstructorInitializer( - cxxCtorInitializer( - unless(isBaseInitializer()), - // Clang builds a CXXConstructExpr only when it knows which - // constructor will be called. In dependent contexts a - // ParenListExpr is generated instead of a CXXConstructExpr, - // filtering out templates automatically for us. - withInitializer(cxxConstructExpr( - has(ignoringParenImpCasts(declRefExpr( - to(parmVarDecl( - hasType(qualType( - // Match only const-ref or a non-const - // value parameters. Rvalues, - // TemplateSpecializationValues and - // const-values shouldn't be modified. - ValuesOnly - ? nonConstValueType() - : anyOf(notTemplateSpecConstRefType(), - nonConstValueType())))) - .bind("Param"))))), - hasDeclaration(cxxConstructorDecl( - isCopyConstructor(), unless(isDeleted()), - hasDeclContext( - cxxRecordDecl(isMoveConstructible()))))))) - .bind("Initializer"))) - .bind("Ctor"), + traverse( + ast_type_traits::TK_AsIs, + cxxConstructorDecl( + forEachConstructorInitializer( + cxxCtorInitializer( + unless(isBaseInitializer()), + // Clang builds a CXXConstructExpr only when it knows + // which constructor will be called. In dependent contexts + // a ParenListExpr is generated instead of a + // CXXConstructExpr, filtering out templates automatically + // for us. + withInitializer(cxxConstructExpr( + has(ignoringParenImpCasts(declRefExpr(to( + parmVarDecl( + hasType(qualType( + // Match only const-ref or a non-const + // value parameters. Rvalues, + // TemplateSpecializationValues and + // const-values shouldn't be modified. + ValuesOnly + ? nonConstValueType() + : anyOf(notTemplateSpecConstRefType(), + nonConstValueType())))) + .bind("Param"))))), + hasDeclaration(cxxConstructorDecl( + isCopyConstructor(), unless(isDeleted()), + hasDeclContext( + cxxRecordDecl(isMoveConstructible()))))))) + .bind("Initializer"))) + .bind("Ctor")), this); } diff --git a/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp b/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp index ade2bec3a98b66..515b2146f06c70 100644 --- a/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ReplaceAutoPtrCheck.cpp @@ -123,9 +123,11 @@ void ReplaceAutoPtrCheck::registerMatchers(MatchFinder *Finder) { callee(cxxMethodDecl(ofClass(AutoPtrDecl))), hasArgument(1, MovableArgumentMatcher)), this); - Finder->addMatcher(cxxConstructExpr(hasType(AutoPtrType), argumentCountIs(1), - hasArgument(0, MovableArgumentMatcher)), - this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, + cxxConstructExpr(hasType(AutoPtrType), argumentCountIs(1), + hasArgument(0, MovableArgumentMatcher))), + this); } void ReplaceAutoPtrCheck::registerPPCallbacks(const SourceManager &SM, diff --git a/clang-tools-extra/clang-tidy/modernize/ReplaceRandomShuffleCheck.cpp b/clang-tools-extra/clang-tidy/modernize/ReplaceRandomShuffleCheck.cpp index e7c2bdb256e1aa..5507729729236b 100644 --- a/clang-tools-extra/clang-tidy/modernize/ReplaceRandomShuffleCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ReplaceRandomShuffleCheck.cpp @@ -32,11 +32,14 @@ void ReplaceRandomShuffleCheck::registerMatchers(MatchFinder *Finder) { const auto End = hasArgument(1, expr()); const auto RandomFunc = hasArgument(2, expr().bind("randomFunc")); Finder->addMatcher( - callExpr(anyOf(allOf(Begin, End, argumentCountIs(2)), - allOf(Begin, End, RandomFunc, argumentCountIs(3))), - hasDeclaration(functionDecl(hasName("::std::random_shuffle"))), - has(implicitCastExpr(has(declRefExpr().bind("name"))))) - .bind("match"), + traverse( + ast_type_traits::TK_AsIs, + callExpr( + anyOf(allOf(Begin, End, argumentCountIs(2)), + allOf(Begin, End, RandomFunc, argumentCountIs(3))), + hasDeclaration(functionDecl(hasName("::std::random_shuffle"))), + has(implicitCastExpr(has(declRefExpr().bind("name"))))) + .bind("match")), this); } diff --git a/clang-tools-extra/clang-tidy/modernize/ReturnBracedInitListCheck.cpp b/clang-tools-extra/clang-tidy/modernize/ReturnBracedInitListCheck.cpp index d37b276d93cf25..d94e1cee227acd 100644 --- a/clang-tools-extra/clang-tidy/modernize/ReturnBracedInitListCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ReturnBracedInitListCheck.cpp @@ -31,11 +31,13 @@ void ReturnBracedInitListCheck::registerMatchers(MatchFinder *Finder) { has(ConstructExpr), has(cxxFunctionalCastExpr(has(ConstructExpr))))); Finder->addMatcher( - functionDecl(isDefinition(), // Declarations don't have return statements. + traverse(ast_type_traits::TK_AsIs, + functionDecl( + isDefinition(), // Declarations don't have return statements. returns(unless(anyOf(builtinType(), autoType()))), hasDescendant(returnStmt(hasReturnValue( has(cxxConstructExpr(has(CtorAsArgument))))))) - .bind("fn"), + .bind("fn")), this); } diff --git a/clang-tools-extra/clang-tidy/modernize/ShrinkToFitCheck.cpp b/clang-tools-extra/clang-tidy/modernize/ShrinkToFitCheck.cpp index 8f6f80cbc9571c..d967e5283fa00d 100644 --- a/clang-tools-extra/clang-tidy/modernize/ShrinkToFitCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ShrinkToFitCheck.cpp @@ -42,7 +42,8 @@ void ShrinkToFitCheck::registerMatchers(MatchFinder *Finder) { on(hasType(hasCanonicalType(hasDeclaration(namedDecl( hasAnyName("std::basic_string", "std::deque", "std::vector")))))), callee(cxxMethodDecl(hasName("swap"))), - has(ignoringParenImpCasts(memberExpr(hasDescendant(CopyCtorCall)))), + has(ignoringParenImpCasts(memberExpr(traverse( + ast_type_traits::TK_AsIs, hasDescendant(CopyCtorCall))))), hasArgument(0, SwapParam.bind("ContainerToShrink")), unless(isInTemplateInstantiation())) .bind("CopyAndSwapTrick"), diff --git a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp index 4791bd6060d652..eed9321d688c0c 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseAutoCheck.cpp @@ -325,7 +325,8 @@ void UseAutoCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { } void UseAutoCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher(makeCombinedMatcher(), this); + Finder->addMatcher(traverse(ast_type_traits::TK_AsIs, makeCombinedMatcher()), + this); } void UseAutoCheck::replaceIterators(const DeclStmt *D, ASTContext *Context) { diff --git a/clang-tools-extra/clang-tidy/modernize/UseBoolLiteralsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseBoolLiteralsCheck.cpp index 65646d6bdad114..5ddda30764fcdb 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseBoolLiteralsCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseBoolLiteralsCheck.cpp @@ -24,22 +24,25 @@ UseBoolLiteralsCheck::UseBoolLiteralsCheck(StringRef Name, void UseBoolLiteralsCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( - implicitCastExpr( - has(ignoringParenImpCasts(integerLiteral().bind("literal"))), - hasImplicitDestinationType(qualType(booleanType())), - unless(isInTemplateInstantiation()), - anyOf(hasParent(explicitCastExpr().bind("cast")), anything())), + traverse( + ast_type_traits::TK_AsIs, + implicitCastExpr( + has(ignoringParenImpCasts(integerLiteral().bind("literal"))), + hasImplicitDestinationType(qualType(booleanType())), + unless(isInTemplateInstantiation()), + anyOf(hasParent(explicitCastExpr().bind("cast")), anything()))), this); Finder->addMatcher( - conditionalOperator( - hasParent(implicitCastExpr( - hasImplicitDestinationType(qualType(booleanType())), - unless(isInTemplateInstantiation()))), - eachOf(hasTrueExpression( - ignoringParenImpCasts(integerLiteral().bind("literal"))), - hasFalseExpression( - ignoringParenImpCasts(integerLiteral().bind("literal"))))), + traverse(ast_type_traits::TK_AsIs, + conditionalOperator( + hasParent(implicitCastExpr( + hasImplicitDestinationType(qualType(booleanType())), + unless(isInTemplateInstantiation()))), + eachOf(hasTrueExpression(ignoringParenImpCasts( + integerLiteral().bind("literal"))), + hasFalseExpression(ignoringParenImpCasts( + integerLiteral().bind("literal")))))), this); } diff --git a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp index b84b0cd865e58d..823b119dace074 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp @@ -109,10 +109,12 @@ void UseEmplaceCheck::registerMatchers(MatchFinder *Finder) { anyOf(has(MakeTuple), has(MakeTupleCtor), HasConstructExpr, has(cxxFunctionalCastExpr(HasConstructExpr)))); - Finder->addMatcher(cxxMemberCallExpr(CallPushBack, has(SoughtParam), - unless(isInTemplateInstantiation())) - .bind("call"), - this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, + cxxMemberCallExpr(CallPushBack, has(SoughtParam), + unless(isInTemplateInstantiation())) + .bind("call")), + this); } void UseEmplaceCheck::check(const MatchFinder::MatchResult &Result) { diff --git a/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp index 09603497e68277..23e48c0a9ab2f1 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp @@ -75,14 +75,17 @@ static bool isCopyConstructorAndCanBeDefaulted(ASTContext *Context, // The initialization of a base class should be a call to a copy // constructor of the base. if (match( - cxxConstructorDecl(forEachConstructorInitializer(cxxCtorInitializer( - isBaseInitializer(), - withInitializer(cxxConstructExpr( - hasType(equalsNode(Base)), - hasDeclaration(cxxConstructorDecl(isCopyConstructor())), - argumentCountIs(1), - hasArgument( - 0, declRefExpr(to(varDecl(equalsNode(Param)))))))))), + traverse(ast_type_traits::TK_AsIs, + cxxConstructorDecl( + forEachConstructorInitializer(cxxCtorInitializer( + isBaseInitializer(), + withInitializer(cxxConstructExpr( + hasType(equalsNode(Base)), + hasDeclaration( + cxxConstructorDecl(isCopyConstructor())), + argumentCountIs(1), + hasArgument(0, declRefExpr(to(varDecl( + equalsNode(Param))))))))))), *Ctor, *Context) .empty()) return false; @@ -92,17 +95,20 @@ static bool isCopyConstructorAndCanBeDefaulted(ASTContext *Context, for (const auto *Field : FieldsToInit) { auto AccessToFieldInParam = accessToFieldInVar(Field, Param); // The initialization is a CXXConstructExpr for class types. - if (match( - cxxConstructorDecl(forEachConstructorInitializer(cxxCtorInitializer( - isMemberInitializer(), forField(equalsNode(Field)), - withInitializer(anyOf( - AccessToFieldInParam, - initListExpr(has(AccessToFieldInParam)), - cxxConstructExpr( - hasDeclaration(cxxConstructorDecl(isCopyConstructor())), - argumentCountIs(1), - hasArgument(0, AccessToFieldInParam))))))), - *Ctor, *Context) + if (match(traverse( + ast_type_traits::TK_AsIs, + cxxConstructorDecl( + forEachConstructorInitializer(cxxCtorInitializer( + isMemberInitializer(), forField(equalsNode(Field)), + withInitializer(anyOf( + AccessToFieldInParam, + initListExpr(has(AccessToFieldInParam)), + cxxConstructExpr( + hasDeclaration( + cxxConstructorDecl(isCopyConstructor())), + argumentCountIs(1), + hasArgument(0, AccessToFieldInParam)))))))), + *Ctor, *Context) .empty()) return false; } @@ -130,8 +136,10 @@ static bool isCopyAssignmentAndCanBeDefaulted(ASTContext *Context, // statement: // return *this; if (Compound->body_empty() || - match(returnStmt(has(ignoringParenImpCasts(unaryOperator( - hasOperatorName("*"), hasUnaryOperand(cxxThisExpr()))))), + match(traverse( + ast_type_traits::TK_AsIs, + returnStmt(has(ignoringParenImpCasts(unaryOperator( + hasOperatorName("*"), hasUnaryOperand(cxxThisExpr())))))), *Compound->body_back(), *Context) .empty()) return false; @@ -145,21 +153,23 @@ static bool isCopyAssignmentAndCanBeDefaulted(ASTContext *Context, // ((Base*)this)->operator=((Base)Other); // // So we are looking for a member call that fulfills: - if (match( - compoundStmt(has(ignoringParenImpCasts(cxxMemberCallExpr( - // - The object is an implicit cast of 'this' to a pointer to - // a base class. - onImplicitObjectArgument( - implicitCastExpr(hasImplicitDestinationType( - pointsTo(type(equalsNode(Base)))), - hasSourceExpression(cxxThisExpr()))), - // - The called method is the operator=. - callee(cxxMethodDecl(isCopyAssignmentOperator())), - // - The argument is (an implicit cast to a Base of) the - // argument taken by "Operator". - argumentCountIs(1), - hasArgument(0, declRefExpr(to(varDecl(equalsNode(Param))))))))), - *Compound, *Context) + if (match(traverse(ast_type_traits::TK_AsIs, + compoundStmt(has(ignoringParenImpCasts(cxxMemberCallExpr( + // - The object is an implicit cast of 'this' to a + // pointer to + // a base class. + onImplicitObjectArgument(implicitCastExpr( + hasImplicitDestinationType( + pointsTo(type(equalsNode(Base)))), + hasSourceExpression(cxxThisExpr()))), + // - The called method is the operator=. + callee(cxxMethodDecl(isCopyAssignmentOperator())), + // - The argument is (an implicit cast to a Base of) + // the argument taken by "Operator". + argumentCountIs(1), + hasArgument(0, declRefExpr(to(varDecl( + equalsNode(Param)))))))))), + *Compound, *Context) .empty()) return false; } @@ -174,11 +184,13 @@ static bool isCopyAssignmentAndCanBeDefaulted(ASTContext *Context, member(fieldDecl(equalsNode(Field)))); auto RHS = accessToFieldInVar(Field, Param); if (match( - compoundStmt(has(ignoringParenImpCasts(stmt(anyOf( - binaryOperator(hasOperatorName("="), hasLHS(LHS), hasRHS(RHS)), - cxxOperatorCallExpr(hasOverloadedOperatorName("="), - argumentCountIs(2), hasArgument(0, LHS), - hasArgument(1, RHS))))))), + traverse(ast_type_traits::TK_AsIs, + compoundStmt(has(ignoringParenImpCasts(stmt(anyOf( + binaryOperator(hasOperatorName("="), hasLHS(LHS), + hasRHS(RHS)), + cxxOperatorCallExpr( + hasOverloadedOperatorName("="), argumentCountIs(2), + hasArgument(0, LHS), hasArgument(1, RHS)))))))), *Compound, *Context) .empty()) return false; diff --git a/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.cpp index bbda8d58f10328..cc4bc05a35dd0c 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.cpp @@ -16,6 +16,10 @@ namespace clang { namespace tidy { namespace modernize { +namespace { +AST_MATCHER(NamedDecl, isValid) { return !Node.isInvalidDecl(); } +} // namespace + UseNoexceptCheck::UseNoexceptCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), NoexceptMacro(Options.get("ReplacementString", "")), @@ -29,20 +33,12 @@ void UseNoexceptCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { void UseNoexceptCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( functionDecl( - cxxMethodDecl( - hasTypeLoc(loc(functionProtoType(hasDynamicExceptionSpec()))), - anyOf(hasOverloadedOperatorName("delete[]"), - hasOverloadedOperatorName("delete"), cxxDestructorDecl())) - .bind("del-dtor")) - .bind("funcDecl"), - this); - - Finder->addMatcher( - functionDecl( + isValid(), hasTypeLoc(loc(functionProtoType(hasDynamicExceptionSpec()))), - unless(anyOf(hasOverloadedOperatorName("delete[]"), - hasOverloadedOperatorName("delete"), - cxxDestructorDecl()))) + optionally(cxxMethodDecl(anyOf(hasAnyOverloadedOperatorName( + "delete[]", "delete"), + cxxDestructorDecl())) + .bind("del-dtor"))) .bind("funcDecl"), this); @@ -80,6 +76,9 @@ void UseNoexceptCheck::check(const MatchFinder::MatchResult &Result) { .castAs() .getExceptionSpecRange(); } + + assert(Range.isValid() && "Exception Source Range is invalid."); + CharSourceRange CRange = Lexer::makeFileCharRange( CharSourceRange::getTokenRange(Range), *Result.SourceManager, Result.Context->getLangOpts()); diff --git a/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.h b/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.h index 4f3ba321483ee1..b87d3e629ff69c 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.h +++ b/clang-tools-extra/clang-tidy/modernize/UseNoexceptCheck.h @@ -41,7 +41,7 @@ class UseNoexceptCheck : public ClangTidyCheck { private: const std::string NoexceptMacro; - bool UseNoexceptFalse; + const bool UseNoexceptFalse; }; } // namespace modernize diff --git a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp index 37e4d24e989854..7e30c174a615f3 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.cpp @@ -41,10 +41,12 @@ StatementMatcher makeCastSequenceMatcher() { unless(hasImplicitDestinationType(qualType(substTemplateTypeParmType()))), unless(hasSourceExpression(hasType(sugaredNullptrType())))); - return castExpr(anyOf(ImplicitCastToNull, - explicitCastExpr(hasDescendant(ImplicitCastToNull))), - unless(hasAncestor(explicitCastExpr()))) - .bind(CastSequence); + return traverse( + ast_type_traits::TK_AsIs, + castExpr(anyOf(ImplicitCastToNull, + explicitCastExpr(hasDescendant(ImplicitCastToNull))), + unless(hasAncestor(explicitCastExpr()))) + .bind(CastSequence)); } bool isReplaceableRange(SourceLocation StartLoc, SourceLocation EndLoc, diff --git a/clang-tools-extra/clang-tidy/objc/NSInvocationArgumentLifetimeCheck.cpp b/clang-tools-extra/clang-tidy/objc/NSInvocationArgumentLifetimeCheck.cpp index 520bdc3b9f12e2..ecbf0953ec6d57 100644 --- a/clang-tools-extra/clang-tidy/objc/NSInvocationArgumentLifetimeCheck.cpp +++ b/clang-tools-extra/clang-tidy/objc/NSInvocationArgumentLifetimeCheck.cpp @@ -101,23 +101,26 @@ fixItHintForVarDecl(const VarDecl *VD, const SourceManager &SM, void NSInvocationArgumentLifetimeCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( - objcMessageExpr( - hasReceiverType(asString("NSInvocation *")), - anyOf(hasSelector("getArgument:atIndex:"), - hasSelector("getReturnValue:")), - hasArgument( - 0, anyOf(hasDescendant(memberExpr(isObjCManagedLifetime())), - hasDescendant(objcIvarRefExpr(isObjCManagedLifetime())), - hasDescendant( - // Reference to variables, but when dereferencing - // to ivars/fields a more-descendent variable - // reference (e.g. self) may match with strong - // object lifetime, leading to an incorrect match. - // Exclude these conditions. - declRefExpr(to(varDecl().bind("var")), - unless(hasParent(implicitCastExpr())), - isObjCManagedLifetime()))))) - .bind("call"), + traverse( + ast_type_traits::TK_AsIs, + objcMessageExpr( + hasReceiverType(asString("NSInvocation *")), + anyOf(hasSelector("getArgument:atIndex:"), + hasSelector("getReturnValue:")), + hasArgument( + 0, + anyOf(hasDescendant(memberExpr(isObjCManagedLifetime())), + hasDescendant(objcIvarRefExpr(isObjCManagedLifetime())), + hasDescendant( + // Reference to variables, but when dereferencing + // to ivars/fields a more-descendent variable + // reference (e.g. self) may match with strong + // object lifetime, leading to an incorrect match. + // Exclude these conditions. + declRefExpr(to(varDecl().bind("var")), + unless(hasParent(implicitCastExpr())), + isObjCManagedLifetime()))))) + .bind("call")), this); } diff --git a/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp b/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp index 38dba7b8970700..84a4ac922fa548 100644 --- a/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/ForRangeCopyCheck.cpp @@ -49,9 +49,11 @@ void ForRangeCopyCheck::registerMatchers(MatchFinder *Finder) { varDecl(HasReferenceOrPointerTypeOrIsAllowed, unless(hasInitializer(expr(hasDescendant(expr(anyOf( materializeTemporaryExpr(), IteratorReturnsValueType))))))); - Finder->addMatcher(cxxForRangeStmt(hasLoopVariable(LoopVar.bind("loopVar"))) - .bind("forRange"), - this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, + cxxForRangeStmt(hasLoopVariable(LoopVar.bind("loopVar"))) + .bind("forRange")), + this); } void ForRangeCopyCheck::check(const MatchFinder::MatchResult &Result) { diff --git a/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp b/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp index a52065540917e9..9cddd2b4d31ce3 100644 --- a/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/ImplicitConversionInLoopCheck.cpp @@ -47,16 +47,19 @@ void ImplicitConversionInLoopCheck::registerMatchers(MatchFinder *Finder) { // CXXOperatorCallExpr, so it should not get caught by the // cxxOperatorCallExpr() matcher. Finder->addMatcher( - cxxForRangeStmt(hasLoopVariable( - varDecl( - hasType(qualType(references(qualType(isConstQualified())))), - hasInitializer( - expr(anyOf(hasDescendant( - cxxOperatorCallExpr().bind("operator-call")), - hasDescendant(unaryOperator(hasOperatorName("*")) - .bind("operator-call")))) - .bind("init"))) - .bind("faulty-var"))), + traverse( + ast_type_traits::TK_AsIs, + cxxForRangeStmt(hasLoopVariable( + varDecl( + hasType(qualType(references(qualType(isConstQualified())))), + hasInitializer( + expr(anyOf( + hasDescendant( + cxxOperatorCallExpr().bind("operator-call")), + hasDescendant(unaryOperator(hasOperatorName("*")) + .bind("operator-call")))) + .bind("init"))) + .bind("faulty-var")))), this); } diff --git a/clang-tools-extra/clang-tidy/performance/InefficientAlgorithmCheck.cpp b/clang-tools-extra/clang-tidy/performance/InefficientAlgorithmCheck.cpp index 8dda7a8022147e..dfea0104614c99 100644 --- a/clang-tools-extra/clang-tidy/performance/InefficientAlgorithmCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/InefficientAlgorithmCheck.cpp @@ -35,7 +35,8 @@ void InefficientAlgorithmCheck::registerMatchers(MatchFinder *Finder) { "::std::unordered_set", "::std::unordered_map", "::std::unordered_multiset", "::std::unordered_multimap")); - const auto Matcher = + const auto Matcher = traverse( + ast_type_traits::TK_AsIs, callExpr( callee(functionDecl(Algorithms)), hasArgument( @@ -54,7 +55,7 @@ void InefficientAlgorithmCheck::registerMatchers(MatchFinder *Finder) { hasDeclaration(equalsBoundNode("IneffContObj"))))))))), hasArgument(2, expr().bind("AlgParam")), unless(isInTemplateInstantiation())) - .bind("IneffAlg"); + .bind("IneffAlg")); Finder->addMatcher(Matcher, this); } diff --git a/clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.cpp b/clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.cpp index 17eb62a41a1d0e..95aa33863d656b 100644 --- a/clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/MoveConstArgCheck.cpp @@ -51,8 +51,10 @@ void MoveConstArgCheck::registerMatchers(MatchFinder *Finder) { MoveCallMatcher, parmVarDecl(hasType(references(isConstQualified())))); Finder->addMatcher(callExpr(ConstParamMatcher).bind("receiving-expr"), this); - Finder->addMatcher(cxxConstructExpr(ConstParamMatcher).bind("receiving-expr"), - this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, + cxxConstructExpr(ConstParamMatcher).bind("receiving-expr")), + this); } void MoveConstArgCheck::check(const MatchFinder::MatchResult &Result) { diff --git a/clang-tools-extra/clang-tidy/performance/MoveConstructorInitCheck.cpp b/clang-tools-extra/clang-tidy/performance/MoveConstructorInitCheck.cpp index 853e07f6001bfc..d09673fa7f23f4 100644 --- a/clang-tools-extra/clang-tidy/performance/MoveConstructorInitCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/MoveConstructorInitCheck.cpp @@ -29,13 +29,15 @@ MoveConstructorInitCheck::MoveConstructorInitCheck(StringRef Name, void MoveConstructorInitCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( - cxxConstructorDecl( - unless(isImplicit()), isMoveConstructor(), - hasAnyConstructorInitializer( - cxxCtorInitializer( - withInitializer(cxxConstructExpr(hasDeclaration( - cxxConstructorDecl(isCopyConstructor()).bind("ctor"))))) - .bind("move-init"))), + traverse(ast_type_traits::TK_AsIs, + cxxConstructorDecl( + unless(isImplicit()), isMoveConstructor(), + hasAnyConstructorInitializer( + cxxCtorInitializer( + withInitializer(cxxConstructExpr(hasDeclaration( + cxxConstructorDecl(isCopyConstructor()) + .bind("ctor"))))) + .bind("move-init")))), this); } diff --git a/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp b/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp index 8ce8bb479ee5c7..057e10d3c21ebc 100644 --- a/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/NoAutomaticMoveCheck.cpp @@ -44,12 +44,14 @@ void NoAutomaticMoveCheck::registerMatchers(MatchFinder *Finder) { pointee(type(equalsBoundNode("SrcT"))))))))))); Finder->addMatcher( - returnStmt( - hasReturnValue(ignoringElidableConstructorCall(ignoringParenImpCasts( - cxxConstructExpr(hasDeclaration(LValueRefCtor), - hasArgument(0, ignoringParenImpCasts(declRefExpr( - to(ConstLocalVariable))))) - .bind("ctor_call"))))), + traverse(ast_type_traits::TK_AsIs, + returnStmt(hasReturnValue( + ignoringElidableConstructorCall(ignoringParenImpCasts( + cxxConstructExpr( + hasDeclaration(LValueRefCtor), + hasArgument(0, ignoringParenImpCasts(declRefExpr( + to(ConstLocalVariable))))) + .bind("ctor_call")))))), this); } diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp index c9ae37d036ca40..f7b21a50203cb1 100644 --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryCopyInitialization.cpp @@ -68,12 +68,13 @@ void UnnecessaryCopyInitialization::registerMatchers(MatchFinder *Finder) { matchers::matchesAnyListedName( AllowedTypes)))))), unless(isImplicit()), - hasInitializer( + hasInitializer(traverse( + ast_type_traits::TK_AsIs, cxxConstructExpr( hasDeclaration(cxxConstructorDecl( isCopyConstructor())), hasArgument(0, CopyCtorArg)) - .bind("ctorCall"))) + .bind("ctorCall")))) .bind("newVarDecl"))) .bind("declStmt"))) .bind("blockStmt"); @@ -96,6 +97,8 @@ void UnnecessaryCopyInitialization::check( const auto *BlockStmt = Result.Nodes.getNodeAs("blockStmt"); const auto *CtorCall = Result.Nodes.getNodeAs("ctorCall"); + TraversalKindScope RAII(*Result.Context, ast_type_traits::TK_AsIs); + // Do not propose fixes if the DeclStmt has multiple VarDecls or in macros // since we cannot place them correctly. bool IssueFix = diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp index 5b71d8996dab97..9dea4240951322 100644 --- a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp +++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp @@ -41,12 +41,13 @@ bool isReferencedOutsideOfCallExpr(const FunctionDecl &Function, bool hasLoopStmtAncestor(const DeclRefExpr &DeclRef, const Decl &Decl, ASTContext &Context) { - auto Matches = - match(decl(forEachDescendant(declRefExpr( - equalsNode(&DeclRef), - unless(hasAncestor(stmt(anyOf(forStmt(), cxxForRangeStmt(), - whileStmt(), doStmt()))))))), - Decl, Context); + auto Matches = match( + traverse(ast_type_traits::TK_AsIs, + decl(forEachDescendant(declRefExpr( + equalsNode(&DeclRef), + unless(hasAncestor(stmt(anyOf(forStmt(), cxxForRangeStmt(), + whileStmt(), doStmt())))))))), + Decl, Context); return Matches.empty(); } @@ -82,10 +83,12 @@ void UnnecessaryValueParamCheck::registerMatchers(MatchFinder *Finder) { matchers::matchesAnyListedName(AllowedTypes))))))), decl().bind("param")); Finder->addMatcher( - functionDecl(hasBody(stmt()), isDefinition(), unless(isImplicit()), - unless(cxxMethodDecl(anyOf(isOverride(), isFinal()))), - has(typeLoc(forEach(ExpensiveValueParamDecl))), - unless(isInstantiated()), decl().bind("functionDecl")), + traverse( + ast_type_traits::TK_AsIs, + functionDecl(hasBody(stmt()), isDefinition(), unless(isImplicit()), + unless(cxxMethodDecl(anyOf(isOverride(), isFinal()))), + has(typeLoc(forEach(ExpensiveValueParamDecl))), + unless(isInstantiated()), decl().bind("functionDecl"))), this); } @@ -93,6 +96,8 @@ void UnnecessaryValueParamCheck::check(const MatchFinder::MatchResult &Result) { const auto *Param = Result.Nodes.getNodeAs("param"); const auto *Function = Result.Nodes.getNodeAs("functionDecl"); + TraversalKindScope RAII(*Result.Context, ast_type_traits::TK_AsIs); + FunctionParmMutationAnalyzer &Analyzer = MutationAnalyzers.try_emplace(Function, *Function, *Result.Context) .first->second; diff --git a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp index 992a3fa11639e8..bcd3e248df77dd 100644 --- a/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ContainerSizeEmptyCheck.cpp @@ -39,18 +39,20 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) { .bind("empty"))) .bind("container"))))))); - const auto WrongUse = anyOf( - hasParent(binaryOperator( - isComparisonOperator(), - hasEitherOperand(ignoringImpCasts(anyOf( - integerLiteral(equals(1)), integerLiteral(equals(0)))))) - .bind("SizeBinaryOp")), - hasParent(implicitCastExpr( - hasImplicitDestinationType(booleanType()), - anyOf( - hasParent(unaryOperator(hasOperatorName("!")).bind("NegOnSize")), - anything()))), - hasParent(explicitCastExpr(hasDestinationType(booleanType())))); + const auto WrongUse = traverse( + ast_type_traits::TK_AsIs, + anyOf( + hasParent(binaryOperator(isComparisonOperator(), + hasEitherOperand(ignoringImpCasts( + anyOf(integerLiteral(equals(1)), + integerLiteral(equals(0)))))) + .bind("SizeBinaryOp")), + hasParent(implicitCastExpr( + hasImplicitDestinationType(booleanType()), + anyOf(hasParent( + unaryOperator(hasOperatorName("!")).bind("NegOnSize")), + anything()))), + hasParent(explicitCastExpr(hasDestinationType(booleanType()))))); Finder->addMatcher( cxxMemberCallExpr(on(expr(anyOf(hasType(ValidContainer), diff --git a/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp b/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp index 18a775e87e3d8d..57b1a0c9e141c6 100644 --- a/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/DeleteNullPointerCheck.cpp @@ -39,13 +39,15 @@ void DeleteNullPointerCheck::registerMatchers(MatchFinder *Finder) { hasOperands(castExpr(hasCastKind(CK_NullToPointer)), PointerExpr)); Finder->addMatcher( - ifStmt(hasCondition(anyOf(PointerCondition, BinaryPointerCheckCondition)), - hasThen(anyOf( - DeleteExpr, DeleteMemberExpr, - compoundStmt(anyOf(has(DeleteExpr), has(DeleteMemberExpr)), - statementCountIs(1)) - .bind("compound")))) - .bind("ifWithDelete"), + traverse(ast_type_traits::TK_AsIs, + ifStmt(hasCondition( + anyOf(PointerCondition, BinaryPointerCheckCondition)), + hasThen(anyOf(DeleteExpr, DeleteMemberExpr, + compoundStmt(anyOf(has(DeleteExpr), + has(DeleteMemberExpr)), + statementCountIs(1)) + .bind("compound")))) + .bind("ifWithDelete")), this); } diff --git a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp index 22fce443a3e0ab..d7a782bfd18207 100644 --- a/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ImplicitBoolConversionCheck.cpp @@ -221,6 +221,9 @@ bool isCastAllowedInCondition(const ImplicitCastExpr *Cast, ASTContext &Context) { std::queue Q; Q.push(Cast); + + TraversalKindScope RAII(Context, ast_type_traits::TK_AsIs); + while (!Q.empty()) { for (const auto &N : Context.getParents(*Q.front())) { const Stmt *S = N.get(); @@ -273,24 +276,25 @@ void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) { binaryOperator(hasOperatorName("^"), hasLHS(implicitCastFromBool), hasRHS(implicitCastFromBool)); Finder->addMatcher( - implicitCastExpr( - anyOf(hasCastKind(CK_IntegralToBoolean), - hasCastKind(CK_FloatingToBoolean), - hasCastKind(CK_PointerToBoolean), - hasCastKind(CK_MemberPointerToBoolean)), - // Exclude case of using if or while statements with variable - // declaration, e.g.: - // if (int var = functionCall()) {} - unless( - hasParent(stmt(anyOf(ifStmt(), whileStmt()), has(declStmt())))), - // Exclude cases common to implicit cast to and from bool. - unless(exceptionCases), unless(has(boolXor)), - // Retrieve also parent statement, to check if we need additional - // parens in replacement. - anyOf(hasParent(stmt().bind("parentStmt")), anything()), - unless(isInTemplateInstantiation()), - unless(hasAncestor(functionTemplateDecl()))) - .bind("implicitCastToBool"), + traverse(ast_type_traits::TK_AsIs, + implicitCastExpr( + anyOf(hasCastKind(CK_IntegralToBoolean), + hasCastKind(CK_FloatingToBoolean), + hasCastKind(CK_PointerToBoolean), + hasCastKind(CK_MemberPointerToBoolean)), + // Exclude case of using if or while statements with variable + // declaration, e.g.: + // if (int var = functionCall()) {} + unless(hasParent( + stmt(anyOf(ifStmt(), whileStmt()), has(declStmt())))), + // Exclude cases common to implicit cast to and from bool. + unless(exceptionCases), unless(has(boolXor)), + // Retrieve also parent statement, to check if we need + // additional parens in replacement. + anyOf(hasParent(stmt().bind("parentStmt")), anything()), + unless(isInTemplateInstantiation()), + unless(hasAncestor(functionTemplateDecl()))) + .bind("implicitCastToBool")), this); auto boolComparison = binaryOperator(hasAnyOperatorName("==", "!="), @@ -304,26 +308,30 @@ void ImplicitBoolConversionCheck::registerMatchers(MatchFinder *Finder) { withInitializer(equalsBoundNode("implicitCastFromBool")), forField(hasBitWidth(1))))); Finder->addMatcher( - implicitCastExpr( - implicitCastFromBool, - // Exclude comparisons of bools, as they are always cast to integers - // in such context: - // bool_expr_a == bool_expr_b - // bool_expr_a != bool_expr_b - unless(hasParent(binaryOperator(anyOf( - boolComparison, boolXor, boolOpAssignment, bitfieldAssignment)))), - implicitCastExpr().bind("implicitCastFromBool"), - unless(hasParent(bitfieldConstruct)), - // Check also for nested casts, for example: bool -> int -> float. - anyOf(hasParent(implicitCastExpr().bind("furtherImplicitCast")), - anything()), - unless(isInTemplateInstantiation()), - unless(hasAncestor(functionTemplateDecl()))), + traverse( + ast_type_traits::TK_AsIs, + implicitCastExpr( + implicitCastFromBool, + // Exclude comparisons of bools, as they are always cast to + // integers in such context: + // bool_expr_a == bool_expr_b + // bool_expr_a != bool_expr_b + unless(hasParent( + binaryOperator(anyOf(boolComparison, boolXor, + boolOpAssignment, bitfieldAssignment)))), + implicitCastExpr().bind("implicitCastFromBool"), + unless(hasParent(bitfieldConstruct)), + // Check also for nested casts, for example: bool -> int -> float. + anyOf(hasParent(implicitCastExpr().bind("furtherImplicitCast")), + anything()), + unless(isInTemplateInstantiation()), + unless(hasAncestor(functionTemplateDecl())))), this); } void ImplicitBoolConversionCheck::check( const MatchFinder::MatchResult &Result) { + if (const auto *CastToBool = Result.Nodes.getNodeAs("implicitCastToBool")) { const auto *Parent = Result.Nodes.getNodeAs("parentStmt"); diff --git a/clang-tools-extra/clang-tidy/readability/MagicNumbersCheck.cpp b/clang-tools-extra/clang-tidy/readability/MagicNumbersCheck.cpp index 86443a155069e9..df2229ae5f0391 100644 --- a/clang-tools-extra/clang-tidy/readability/MagicNumbersCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/MagicNumbersCheck.cpp @@ -119,6 +119,9 @@ void MagicNumbersCheck::registerMatchers(MatchFinder *Finder) { } void MagicNumbersCheck::check(const MatchFinder::MatchResult &Result) { + + TraversalKindScope RAII(*Result.Context, ast_type_traits::TK_AsIs); + checkBoundMatch(Result, "integer"); checkBoundMatch(Result, "float"); } diff --git a/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp b/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp index cf31ad00d95c7e..ee087e3b3133c6 100644 --- a/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/MakeMemberFunctionConstCheck.cpp @@ -210,21 +210,23 @@ AST_MATCHER(CXXMethodDecl, usesThisAsConst) { void MakeMemberFunctionConstCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( - cxxMethodDecl( - isDefinition(), isUserProvided(), - unless(anyOf( - isExpansionInSystemHeader(), isVirtual(), isConst(), isStatic(), - hasTrivialBody(), cxxConstructorDecl(), cxxDestructorDecl(), - isTemplate(), isDependentContext(), - ofClass(anyOf( - isLambda(), - hasAnyDependentBases()) // Method might become virtual - // depending on template base class. - ), - isInsideMacroDefinition(), - hasCanonicalDecl(isInsideMacroDefinition()))), - usesThisAsConst()) - .bind("x"), + traverse( + ast_type_traits::TK_AsIs, + cxxMethodDecl( + isDefinition(), isUserProvided(), + unless(anyOf( + isExpansionInSystemHeader(), isVirtual(), isConst(), + isStatic(), hasTrivialBody(), cxxConstructorDecl(), + cxxDestructorDecl(), isTemplate(), isDependentContext(), + ofClass(anyOf(isLambda(), + hasAnyDependentBases()) // Method might become + // virtual depending on + // template base class. + ), + isInsideMacroDefinition(), + hasCanonicalDecl(isInsideMacroDefinition()))), + usesThisAsConst()) + .bind("x")), this); } diff --git a/clang-tools-extra/clang-tidy/readability/MisplacedArrayIndexCheck.cpp b/clang-tools-extra/clang-tidy/readability/MisplacedArrayIndexCheck.cpp index 7b39012b7693aa..c5112da413db2c 100644 --- a/clang-tools-extra/clang-tidy/readability/MisplacedArrayIndexCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/MisplacedArrayIndexCheck.cpp @@ -19,10 +19,12 @@ namespace tidy { namespace readability { void MisplacedArrayIndexCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher(arraySubscriptExpr(hasLHS(hasType(isInteger())), - hasRHS(hasType(isAnyPointer()))) - .bind("expr"), - this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, + arraySubscriptExpr(hasLHS(hasType(isInteger())), + hasRHS(hasType(isAnyPointer()))) + .bind("expr")), + this); } void MisplacedArrayIndexCheck::check(const MatchFinder::MatchResult &Result) { diff --git a/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp b/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp index 9d5a18f9358509..688547ca297530 100644 --- a/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp @@ -28,11 +28,13 @@ void NonConstParameterCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher(declRefExpr().bind("Ref"), this); // Analyse parameter usage in function. - Finder->addMatcher(stmt(anyOf(unaryOperator(hasAnyOperatorName("++", "--")), - binaryOperator(), callExpr(), returnStmt(), - cxxConstructExpr())) - .bind("Mark"), - this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, + stmt(anyOf(unaryOperator(hasAnyOperatorName("++", "--")), + binaryOperator(), callExpr(), returnStmt(), + cxxConstructExpr())) + .bind("Mark")), + this); Finder->addMatcher(varDecl(hasInitializer(anything())).bind("Mark"), this); } diff --git a/clang-tools-extra/clang-tidy/readability/RedundantFunctionPtrDereferenceCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantFunctionPtrDereferenceCheck.cpp index f2360a09149fe0..56565ff2115c0f 100644 --- a/clang-tools-extra/clang-tidy/readability/RedundantFunctionPtrDereferenceCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/RedundantFunctionPtrDereferenceCheck.cpp @@ -17,10 +17,11 @@ namespace tidy { namespace readability { void RedundantFunctionPtrDereferenceCheck::registerMatchers(MatchFinder *Finder) { - Finder->addMatcher(unaryOperator(hasOperatorName("*"), - has(implicitCastExpr( - hasCastKind(CK_FunctionToPointerDecay)))) - .bind("op"), + Finder->addMatcher(traverse(ast_type_traits::TK_AsIs, + unaryOperator(hasOperatorName("*"), + has(implicitCastExpr(hasCastKind( + CK_FunctionToPointerDecay)))) + .bind("op")), this); } diff --git a/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp index 09be12a71926c7..027146f12aad52 100644 --- a/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp @@ -33,17 +33,19 @@ void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) { .bind("construct"); Finder->addMatcher( - cxxConstructorDecl( - unless(isDelegatingConstructor()), - ofClass(unless( - anyOf(isUnion(), ast_matchers::isTemplateInstantiation()))), - forEachConstructorInitializer( - cxxCtorInitializer( - isWritten(), withInitializer(ignoringImplicit(Construct)), - unless(forField(hasType(isConstQualified()))), - unless(forField(hasParent(recordDecl(isUnion()))))) - .bind("init"))) - .bind("constructor"), + traverse( + ast_type_traits::TK_AsIs, + cxxConstructorDecl( + unless(isDelegatingConstructor()), + ofClass(unless( + anyOf(isUnion(), ast_matchers::isTemplateInstantiation()))), + forEachConstructorInitializer( + cxxCtorInitializer( + isWritten(), withInitializer(ignoringImplicit(Construct)), + unless(forField(hasType(isConstQualified()))), + unless(forField(hasParent(recordDecl(isUnion()))))) + .bind("init"))) + .bind("constructor")), this); } diff --git a/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp index e41cdfcc08d8e6..bea02a6ba111b2 100644 --- a/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/RedundantStringCStrCheck.cpp @@ -96,11 +96,13 @@ void RedundantStringCStrCheck::registerMatchers( // Detect redundant 'c_str()' calls through a string constructor. // If CxxConstructExpr is the part of some CallExpr we need to // check that matched ParamDecl of the ancestor CallExpr is not rvalue. - Finder->addMatcher(cxxConstructExpr(StringConstructorExpr, - hasArgument(0, StringCStrCallExpr), - unless(hasParent(materializeTemporaryExpr( - unless(isBoundToLValue()))))), - this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, + cxxConstructExpr(StringConstructorExpr, + hasArgument(0, StringCStrCallExpr), + unless(hasParent(materializeTemporaryExpr( + unless(isBoundToLValue())))))), + this); // Detect: 's == str.c_str()' -> 's == str' Finder->addMatcher( @@ -153,20 +155,22 @@ void RedundantStringCStrCheck::registerMatchers( // Detect redundant 'c_str()' calls through a StringRef constructor. Finder->addMatcher( - cxxConstructExpr( - // Implicit constructors of these classes are overloaded - // wrt. string types and they internally make a StringRef - // referring to the argument. Passing a string directly to - // them is preferred to passing a char pointer. - hasDeclaration(cxxMethodDecl(hasAnyName( - "::llvm::StringRef::StringRef", "::llvm::Twine::Twine"))), - argumentCountIs(1), - // The only argument must have the form x.c_str() or p->c_str() - // where the method is string::c_str(). StringRef also has - // a constructor from string which is more efficient (avoids - // strlen), so we can construct StringRef from the string - // directly. - hasArgument(0, StringCStrCallExpr)), + traverse( + ast_type_traits::TK_AsIs, + cxxConstructExpr( + // Implicit constructors of these classes are overloaded + // wrt. string types and they internally make a StringRef + // referring to the argument. Passing a string directly to + // them is preferred to passing a char pointer. + hasDeclaration(cxxMethodDecl(hasAnyName( + "::llvm::StringRef::StringRef", "::llvm::Twine::Twine"))), + argumentCountIs(1), + // The only argument must have the form x.c_str() or p->c_str() + // where the method is string::c_str(). StringRef also has + // a constructor from string which is more efficient (avoids + // strlen), so we can construct StringRef from the string + // directly. + hasArgument(0, StringCStrCallExpr))), this); } diff --git a/clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp index 6c54ca874401c1..e5825bc4f0e331 100644 --- a/clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/RedundantStringInitCheck.cpp @@ -96,17 +96,19 @@ void RedundantStringInitCheck::registerMatchers(MatchFinder *Finder) { const auto StringType = hasType(hasUnqualifiedDesugaredType( recordType(hasDeclaration(cxxRecordDecl(hasStringTypeName))))); - const auto EmptyStringInit = expr(ignoringImplicit( - anyOf(EmptyStringCtorExpr, EmptyStringCtorExprWithTemporaries))); + const auto EmptyStringInit = + traverse(ast_type_traits::TK_AsIs, expr(ignoringImplicit( + anyOf(EmptyStringCtorExpr, EmptyStringCtorExprWithTemporaries)))); // Match a variable declaration with an empty string literal as initializer. // Examples: // string foo = ""; // string bar(""); Finder->addMatcher( - namedDecl( - varDecl(StringType, hasInitializer(EmptyStringInit)).bind("vardecl"), - unless(parmVarDecl())), + traverse(ast_type_traits::TK_AsIs, + namedDecl(varDecl(StringType, hasInitializer(EmptyStringInit)) + .bind("vardecl"), + unless(parmVarDecl()))), this); // Match a field declaration with an empty string literal as initializer. Finder->addMatcher( diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp index e82324578711e7..19d40c54f12c71 100644 --- a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp @@ -31,10 +31,12 @@ void StringCompareCheck::registerMatchers(MatchFinder *Finder) { callee(memberExpr().bind("str1"))); // First and second case: cast str.compare(str) to boolean. - Finder->addMatcher(implicitCastExpr(hasImplicitDestinationType(booleanType()), - has(StrCompare)) - .bind("match1"), - this); + Finder->addMatcher( + traverse(ast_type_traits::TK_AsIs, + implicitCastExpr(hasImplicitDestinationType(booleanType()), + has(StrCompare)) + .bind("match1")), + this); // Third and fourth case: str.compare(str) == 0 and str.compare(str) != 0. Finder->addMatcher( diff --git a/clang-tools-extra/clang-tidy/readability/UppercaseLiteralSuffixCheck.cpp b/clang-tools-extra/clang-tidy/readability/UppercaseLiteralSuffixCheck.cpp index 70d2a10ae2d857..aab45faa6cb3a7 100644 --- a/clang-tools-extra/clang-tidy/readability/UppercaseLiteralSuffixCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/UppercaseLiteralSuffixCheck.cpp @@ -196,12 +196,12 @@ void UppercaseLiteralSuffixCheck::registerMatchers(MatchFinder *Finder) { // Sadly, we can't check whether the literal has suffix or not. // E.g. i32 suffix still results in 'BuiltinType::Kind::Int'. // And such an info is not stored in the *Literal itself. - Finder->addMatcher( + Finder->addMatcher(traverse(TK_AsIs, stmt(eachOf(integerLiteral().bind(IntegerLiteralCheck::Name), floatLiteral().bind(FloatingLiteralCheck::Name)), unless(anyOf(hasParent(userDefinedLiteral()), hasAncestor(isImplicit()), - hasAncestor(substNonTypeTemplateParmExpr())))), + hasAncestor(substNonTypeTemplateParmExpr()))))), this); } diff --git a/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp b/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp index 3505f31c92a2a0..8fddf4d4996aad 100644 --- a/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp +++ b/clang-tools-extra/clang-tidy/utils/ExprSequence.cpp @@ -28,6 +28,7 @@ static SmallVector getParentStmts(const Stmt *S, ASTContext *Context) { SmallVector Result; + TraversalKindScope RAII(*Context, ast_type_traits::TK_AsIs); DynTypedNodeList Parents = Context->getParents(*S); SmallVector NodesToProcess(Parents.begin(), diff --git a/clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.cpp b/clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.cpp index d3fac14f713d38..d816f0ba1866d6 100644 --- a/clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.cpp +++ b/clang-tools-extra/clang-tidy/zircon/TemporaryObjectsCheck.cpp @@ -36,10 +36,11 @@ void TemporaryObjectsCheck::registerMatchers(MatchFinder *Finder) { // Matcher for user-defined constructors. Finder->addMatcher( - cxxConstructExpr(hasParent(cxxFunctionalCastExpr()), - hasDeclaration(cxxConstructorDecl( - hasParent(cxxRecordDecl(matchesAnyName(Names)))))) - .bind("temps"), + traverse(ast_type_traits::TK_AsIs, + cxxConstructExpr(hasParent(cxxFunctionalCastExpr()), + hasDeclaration(cxxConstructorDecl(hasParent( + cxxRecordDecl(matchesAnyName(Names)))))) + .bind("temps")), this); } diff --git a/clang-tools-extra/clangd/Hover.cpp b/clang-tools-extra/clangd/Hover.cpp index 3d0430b57931d9..e2a3a0dd62f529 100644 --- a/clang-tools-extra/clangd/Hover.cpp +++ b/clang-tools-extra/clangd/Hover.cpp @@ -468,6 +468,7 @@ HoverInfo getHoverContents(const NamedDecl *D, const SymbolIndex *Index) { HoverInfo HI; const ASTContext &Ctx = D->getASTContext(); + HI.AccessSpecifier = getAccessSpelling(D->getAccess()).str(); HI.NamespaceScope = getNamespaceScope(D); if (!HI.NamespaceScope->empty()) HI.NamespaceScope->append("::"); @@ -835,9 +836,12 @@ markup::Document HoverInfo::present() const { ScopeComment = "// In namespace " + llvm::StringRef(*NamespaceScope).rtrim(':').str() + '\n'; } + std::string DefinitionWithAccess = !AccessSpecifier.empty() + ? AccessSpecifier + ": " + Definition + : Definition; // Note that we don't print anything for global namespace, to not annoy // non-c++ projects or projects that are not making use of namespaces. - Output.addCodeBlock(ScopeComment + Definition); + Output.addCodeBlock(ScopeComment + DefinitionWithAccess); } return Output; } diff --git a/clang-tools-extra/clangd/Hover.h b/clang-tools-extra/clangd/Hover.h index 931e1c2363a45b..b712d844e33d08 100644 --- a/clang-tools-extra/clangd/Hover.h +++ b/clang-tools-extra/clangd/Hover.h @@ -59,6 +59,9 @@ struct HoverInfo { /// Source code containing the definition of the symbol. std::string Definition; + /// Access specifier for declarations inside class/struct/unions, empty for + /// others. + std::string AccessSpecifier; /// Pretty-printed variable type. /// Set only for variables. llvm::Optional Type; diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp index 9d9c5eff8c6823..d3eaa92d4c1ac4 100644 --- a/clang-tools-extra/clangd/Preamble.cpp +++ b/clang-tools-extra/clangd/Preamble.cpp @@ -104,24 +104,6 @@ class CppFilePreambleCallbacks : public PreambleCallbacks { const SourceManager *SourceMgr = nullptr; }; -// Runs preprocessor over preamble section. -class PreambleOnlyAction : public PreprocessorFrontendAction { -protected: - void ExecuteAction() override { - Preprocessor &PP = getCompilerInstance().getPreprocessor(); - auto &SM = PP.getSourceManager(); - PP.EnterMainSourceFile(); - auto Bounds = ComputePreambleBounds(getCompilerInstance().getLangOpts(), - SM.getBuffer(SM.getMainFileID()), 0); - Token Tok; - do { - PP.Lex(Tok); - assert(SM.isInMainFile(Tok.getLocation())); - } while (Tok.isNot(tok::eof) && - SM.getDecomposedLoc(Tok.getLocation()).second < Bounds.Size); - } -}; - /// Gets the includes in the preamble section of the file by running /// preprocessor over \p Contents. Returned includes do not contain resolved /// paths. \p VFS and \p Cmd is used to build the compiler invocation, which @@ -142,8 +124,15 @@ scanPreambleIncludes(llvm::StringRef Contents, "failed to create compiler invocation"); CI->getDiagnosticOpts().IgnoreWarnings = true; auto ContentsBuffer = llvm::MemoryBuffer::getMemBuffer(Contents); + // This means we're scanning (though not preprocessing) the preamble section + // twice. However, it's important to precisely follow the preamble bounds used + // elsewhere. + auto Bounds = + ComputePreambleBounds(*CI->getLangOpts(), ContentsBuffer.get(), 0); + auto PreambleContents = + llvm::MemoryBuffer::getMemBufferCopy(Contents.substr(0, Bounds.Size)); auto Clang = prepareCompilerInstance( - std::move(CI), nullptr, std::move(ContentsBuffer), + std::move(CI), nullptr, std::move(PreambleContents), // Provide an empty FS to prevent preprocessor from performing IO. This // also implies missing resolved paths for includes. new llvm::vfs::InMemoryFileSystem, IgnoreDiags); @@ -152,7 +141,7 @@ scanPreambleIncludes(llvm::StringRef Contents, "compiler instance had no inputs"); // We are only interested in main file includes. Clang->getPreprocessorOpts().SingleFileParseMode = true; - PreambleOnlyAction Action; + PreprocessOnlyAction Action; if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) return llvm::createStringError(llvm::inconvertibleErrorCode(), "failed BeginSourceFile"); diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp index 1d82763b6a3cfe..1fc0e0348d0939 100644 --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -438,8 +438,11 @@ locateSymbolTextually(const SpelledWord &Word, ParsedAST &AST, ScoredResults.push_back({Score, std::move(Located)}); }); - if (TooMany) + if (TooMany) { + vlog("Heuristic index lookup for {0} returned too many candidates, ignored", + Word.Text); return {}; + } llvm::sort(ScoredResults, [](const ScoredLocatedSymbol &A, const ScoredLocatedSymbol &B) { @@ -448,6 +451,10 @@ locateSymbolTextually(const SpelledWord &Word, ParsedAST &AST, std::vector Results; for (auto &Res : std::move(ScoredResults)) Results.push_back(std::move(Res.second)); + if (Results.empty()) + vlog("No heuristic index definition for {0}", Word.Text); + else + log("Found definition heuristically in index for {0}", Word.Text); return Results; } @@ -570,13 +577,22 @@ std::vector locateSymbolAt(ParsedAST &AST, Position Pos, // Is the same word nearby a real identifier that might refer to something? if (const syntax::Token *NearbyIdent = findNearbyIdentifier(*Word, AST.getTokens())) { - if (auto Macro = locateMacroReferent(*NearbyIdent, AST, *MainFilePath)) + if (auto Macro = locateMacroReferent(*NearbyIdent, AST, *MainFilePath)) { + log("Found macro definition heuristically using nearby identifier {0}", + Word->Text); return {*std::move(Macro)}; + } ASTResults = locateASTReferent(NearbyIdent->location(), NearbyIdent, AST, *MainFilePath, Index, /*NodeKind=*/nullptr); - if (!ASTResults.empty()) + if (!ASTResults.empty()) { + log("Found definition heuristically using nearby identifier {0}", + NearbyIdent->text(SM)); return ASTResults; + } else { + vlog("No definition found using nearby identifier {0} at {1}", + Word->Text, Word->Location.printToString(SM)); + } } // No nearby word, or it didn't refer to anything either. Try the index. auto TextualResults = diff --git a/clang-tools-extra/clangd/index/IndexAction.cpp b/clang-tools-extra/clangd/index/IndexAction.cpp index 9f294d4ab92529..aa65008b51c004 100644 --- a/clang-tools-extra/clangd/index/IndexAction.cpp +++ b/clang-tools-extra/clangd/index/IndexAction.cpp @@ -132,11 +132,19 @@ class IndexAction : public ASTFrontendAction { std::function RefsCallback, std::function RelationsCallback, std::function IncludeGraphCallback) - : SymbolsCallback(SymbolsCallback), - RefsCallback(RefsCallback), RelationsCallback(RelationsCallback), + : SymbolsCallback(SymbolsCallback), RefsCallback(RefsCallback), + RelationsCallback(RelationsCallback), IncludeGraphCallback(IncludeGraphCallback), Collector(C), Includes(std::move(Includes)), Opts(Opts), - PragmaHandler(collectIWYUHeaderMaps(this->Includes.get())) {} + PragmaHandler(collectIWYUHeaderMaps(this->Includes.get())) { + this->Opts.ShouldTraverseDecl = [this](const Decl *D) { + auto &SM = D->getASTContext().getSourceManager(); + auto FID = SM.getFileID(SM.getExpansionLoc(D->getLocation())); + if (!FID.isValid()) + return true; + return Collector->shouldIndexFile(FID); + }; + } std::unique_ptr CreateASTConsumer(CompilerInstance &CI, llvm::StringRef InFile) override { @@ -146,15 +154,8 @@ class IndexAction : public ASTFrontendAction { CI.getPreprocessor().addPPCallbacks( std::make_unique(CI.getSourceManager(), IG)); - return index::createIndexingASTConsumer( - Collector, Opts, CI.getPreprocessorPtr(), - /*ShouldSkipFunctionBody=*/[this](const Decl *D) { - auto &SM = D->getASTContext().getSourceManager(); - auto FID = SM.getFileID(SM.getExpansionLoc(D->getLocation())); - if (!FID.isValid()) - return false; - return !Collector->shouldIndexFile(FID); - }); + return index::createIndexingASTConsumer(Collector, Opts, + CI.getPreprocessorPtr()); } bool BeginInvocation(CompilerInstance &CI) override { diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp index 405ff90a5945cf..63a5ba6cb99883 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp @@ -317,18 +317,16 @@ SourceRange getDeletionRange(const FunctionDecl *FD, const syntax::TokenBuffer &TokBuf) { auto DeletionRange = FD->getBody()->getSourceRange(); if (auto *CD = llvm::dyn_cast(FD)) { - const auto &SM = TokBuf.sourceManager(); // AST doesn't contain the location for ":" in ctor initializers. Therefore // we find it by finding the first ":" before the first ctor initializer. SourceLocation InitStart; // Find the first initializer. for (const auto *CInit : CD->inits()) { - // We don't care about in-class initializers. - if (CInit->isInClassMemberInitializer()) + // SourceOrder is -1 for implicit initializers. + if (CInit->getSourceOrder() != 0) continue; - if (InitStart.isInvalid() || - SM.isBeforeInTranslationUnit(CInit->getSourceLocation(), InitStart)) - InitStart = CInit->getSourceLocation(); + InitStart = CInit->getSourceLocation(); + break; } if (InitStart.isValid()) { auto Toks = TokBuf.expandedTokens(CD->getSourceRange()); diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp index 031f57f954cb2c..cab6c97cf121e4 100644 --- a/clang-tools-extra/clangd/tool/ClangdMain.cpp +++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp @@ -274,11 +274,8 @@ list TweakList{ opt CrossFileRename{ "cross-file-rename", cat(Features), - desc("Enable cross-file rename feature. Note that this feature is " - "experimental and may lead to broken code or incomplete rename " - "results"), - init(false), - Hidden, + desc("Enable cross-file rename feature."), + init(true), }; opt RecoveryAST{ diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index e5ff0ee364d83c..dc818ea6619385 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -12,6 +12,7 @@ #include "TestIndex.h" #include "TestTU.h" #include "index/MemIndex.h" +#include "clang/Basic/Specifiers.h" #include "clang/Index/IndexSymbol.h" #include "llvm/ADT/None.h" #include "llvm/ADT/StringRef.h" @@ -79,6 +80,7 @@ TEST(Hover, Structured) { HI.Type = "char"; HI.Offset = 0; HI.Size = 1; + HI.AccessSpecifier = "public"; }}, // Local to class method. {R"cpp( @@ -115,6 +117,7 @@ TEST(Hover, Structured) { HI.Type = "char"; HI.Offset = 0; HI.Size = 1; + HI.AccessSpecifier = "public"; }}, // Struct definition shows size. {R"cpp( @@ -344,6 +347,7 @@ class Foo {})cpp"; HI.Kind = index::SymbolKind::Constructor; HI.Definition = "X()"; HI.Parameters.emplace(); + HI.AccessSpecifier = "public"; }}, {"class X { [[^~]]X(); };", // FIXME: Should be [[~X]]() [](HoverInfo &HI) { @@ -353,6 +357,7 @@ class Foo {})cpp"; HI.Kind = index::SymbolKind::Destructor; HI.Definition = "~X()"; HI.Parameters.emplace(); + HI.AccessSpecifier = "private"; }}, {"class X { [[op^erator]] int(); };", [](HoverInfo &HI) { @@ -362,6 +367,7 @@ class Foo {})cpp"; HI.Kind = index::SymbolKind::ConversionFunction; HI.Definition = "operator int()"; HI.Parameters.emplace(); + HI.AccessSpecifier = "private"; }}, {"class X { operator [[^X]](); };", [](HoverInfo &HI) { @@ -494,6 +500,7 @@ class Foo {})cpp"; HI.NamespaceScope = ""; HI.LocalScope = "Add<1, 2>::"; HI.Value = "3"; + HI.AccessSpecifier = "public"; }}, {R"cpp( constexpr int answer() { return 40 + 2; } @@ -606,6 +613,7 @@ class Foo {})cpp"; HI.Definition = "typename T = int"; HI.LocalScope = "foo::"; HI.Type = "typename"; + HI.AccessSpecifier = "public"; }}, {// TemplateTemplate Type Parameter R"cpp( @@ -618,6 +626,7 @@ class Foo {})cpp"; HI.Definition = "template class T"; HI.LocalScope = "foo::"; HI.Type = "template class"; + HI.AccessSpecifier = "public"; }}, {// NonType Template Parameter R"cpp( @@ -630,6 +639,7 @@ class Foo {})cpp"; HI.Definition = "int T = 5"; HI.LocalScope = "foo::"; HI.Type = "int"; + HI.AccessSpecifier = "public"; }}, {// Getter @@ -646,6 +656,7 @@ class Foo {})cpp"; HI.Type = "float ()"; HI.ReturnType = "float"; HI.Parameters.emplace(); + HI.AccessSpecifier = "public"; }}, {// Setter R"cpp( @@ -664,6 +675,7 @@ class Foo {})cpp"; HI.Parameters->emplace_back(); HI.Parameters->back().Type = "float"; HI.Parameters->back().Name = "v"; + HI.AccessSpecifier = "public"; }}, {// Setter (builder) R"cpp( @@ -682,6 +694,7 @@ class Foo {})cpp"; HI.Parameters->emplace_back(); HI.Parameters->back().Type = "float"; HI.Parameters->back().Name = "v"; + HI.AccessSpecifier = "public"; }}, }; for (const auto &Case : Cases) { @@ -715,6 +728,7 @@ class Foo {})cpp"; EXPECT_EQ(H->Value, Expected.Value); EXPECT_EQ(H->Size, Expected.Size); EXPECT_EQ(H->Offset, Expected.Offset); + EXPECT_EQ(H->AccessSpecifier, Expected.AccessSpecifier); } } @@ -1964,7 +1978,51 @@ Size: 4 bytes // In test::Bar def)", }, - }; + { + [](HoverInfo &HI) { + HI.Kind = index::SymbolKind::Field; + HI.AccessSpecifier = "public"; + HI.Name = "foo"; + HI.LocalScope = "test::Bar::"; + HI.Definition = "def"; + }, + R"(field foo + +// In test::Bar +public: def)", + }, + { + [](HoverInfo &HI) { + HI.Definition = "int method()"; + HI.AccessSpecifier = "protected"; + HI.Kind = index::SymbolKind::InstanceMethod; + HI.NamespaceScope = ""; + HI.LocalScope = "cls::"; + HI.Name = "method"; + HI.Parameters.emplace(); + HI.ReturnType = "int"; + HI.Type = "int ()"; + }, + R"(instance-method method + +→ int + +// In cls +protected: int method())", + }, + { + [](HoverInfo &HI) { + HI.Kind = index::SymbolKind::Union; + HI.AccessSpecifier = "private"; + HI.Name = "foo"; + HI.NamespaceScope = "ns1::"; + HI.Definition = "union foo {}"; + }, + R"(union foo + +// In namespace ns1 +private: union foo {})", + }}; for (const auto &C : Cases) { HoverInfo HI; diff --git a/clang-tools-extra/clangd/unittests/IndexActionTests.cpp b/clang-tools-extra/clangd/unittests/IndexActionTests.cpp index 6441d019c7e186..31e1bc573290fb 100644 --- a/clang-tools-extra/clangd/unittests/IndexActionTests.cpp +++ b/clang-tools-extra/clangd/unittests/IndexActionTests.cpp @@ -19,6 +19,7 @@ namespace { using ::testing::AllOf; using ::testing::ElementsAre; +using ::testing::EndsWith; using ::testing::Not; using ::testing::Pair; using ::testing::UnorderedElementsAre; @@ -75,8 +76,7 @@ class IndexActionTest : public ::testing::Test { new FileManager(FileSystemOptions(), InMemoryFileSystem)); auto Action = createStaticIndexingAction( - SymbolCollector::Options(), - [&](SymbolSlab S) { IndexFile.Symbols = std::move(S); }, + Opts, [&](SymbolSlab S) { IndexFile.Symbols = std::move(S); }, [&](RefSlab R) { IndexFile.Refs = std::move(R); }, [&](RelationSlab R) { IndexFile.Relations = std::move(R); }, [&](IncludeGraph IG) { IndexFile.Sources = std::move(IG); }); @@ -99,11 +99,12 @@ class IndexActionTest : public ::testing::Test { void addFile(llvm::StringRef Path, llvm::StringRef Content) { InMemoryFileSystem->addFile(Path, 0, - llvm::MemoryBuffer::getMemBuffer(Content)); + llvm::MemoryBuffer::getMemBufferCopy(Content)); FilePaths.push_back(std::string(Path)); } protected: + SymbolCollector::Options Opts; std::vector FilePaths; llvm::IntrusiveRefCntPtr InMemoryFileSystem; }; @@ -250,6 +251,36 @@ TEST_F(IndexActionTest, NoWarnings) { EXPECT_THAT(*IndexFile.Symbols, ElementsAre(HasName("foo"), HasName("bar"))); } +TEST_F(IndexActionTest, SkipFiles) { + std::string MainFilePath = testPath("main.cpp"); + addFile(MainFilePath, R"cpp( + // clang-format off + #include "good.h" + #include "bad.h" + // clang-format on + )cpp"); + addFile(testPath("good.h"), R"cpp( + struct S { int s; }; + void f1() { S f; } + auto unskippable1() { return S(); } + )cpp"); + addFile(testPath("bad.h"), R"cpp( + struct T { S t; }; + void f2() { S f; } + auto unskippable2() { return S(); } + )cpp"); + Opts.FileFilter = [](const SourceManager &SM, FileID F) { + return !SM.getFileEntryForID(F)->getName().endswith("bad.h"); + }; + IndexFileIn IndexFile = runIndexingAction(MainFilePath, {"-std=c++14"}); + EXPECT_THAT(*IndexFile.Symbols, + UnorderedElementsAre(HasName("S"), HasName("s"), HasName("f1"), + HasName("unskippable1"))); + for (const auto &Pair : *IndexFile.Refs) + for (const auto &Ref : Pair.second) + EXPECT_THAT(Ref.Location.FileURI, EndsWith("good.h")); +} + } // namespace } // namespace clangd } // namespace clang diff --git a/clang-tools-extra/clangd/unittests/PreambleTests.cpp b/clang-tools-extra/clangd/unittests/PreambleTests.cpp index c1801980b1d509..db615e6e66e132 100644 --- a/clang-tools-extra/clangd/unittests/PreambleTests.cpp +++ b/clang-tools-extra/clangd/unittests/PreambleTests.cpp @@ -118,6 +118,11 @@ TEST(PreamblePatchTest, IncludeParsing) { ^#include "a.h" #include )cpp", + // Directive is not part of preamble if it is not the token immediately + // followed by the hash (#). + R"cpp( + ^#include "a.h" + #/**/include )cpp", }; for (const auto Case : Cases) { diff --git a/clang-tools-extra/clangd/unittests/TweakTests.cpp b/clang-tools-extra/clangd/unittests/TweakTests.cpp index b0a941dae5d2ce..319d9e088c2d84 100644 --- a/clang-tools-extra/clangd/unittests/TweakTests.cpp +++ b/clang-tools-extra/clangd/unittests/TweakTests.cpp @@ -2059,21 +2059,57 @@ TEST_F(DefineOutlineTest, ApplyTest) { "void foo(int x, int y = 5, int = 2, int (*foo)(int) = nullptr) ;", "void foo(int x, int y , int , int (*foo)(int) ) {}", }, - // Ctor initializers. + // Constructors + { + R"cpp( + class Foo {public: Foo(); Foo(int);}; + class Bar { + Ba^r() {} + Bar(int x) : f1(x) {} + Foo f1; + Foo f2 = 2; + };)cpp", + R"cpp( + class Foo {public: Foo(); Foo(int);}; + class Bar { + Bar() ; + Bar(int x) : f1(x) {} + Foo f1; + Foo f2 = 2; + };)cpp", + "Bar::Bar() {}\n", + }, + // Ctor with initializer. + { + R"cpp( + class Foo {public: Foo(); Foo(int);}; + class Bar { + Bar() {} + B^ar(int x) : f1(x), f2(3) {} + Foo f1; + Foo f2 = 2; + };)cpp", + R"cpp( + class Foo {public: Foo(); Foo(int);}; + class Bar { + Bar() {} + Bar(int x) ; + Foo f1; + Foo f2 = 2; + };)cpp", + "Bar::Bar(int x) : f1(x), f2(3) {}\n", + }, + // Ctor initializer with attribute. { R"cpp( class Foo { - int y = 2; F^oo(int z) __attribute__((weak)) : bar(2){} int bar; - int z = 2; };)cpp", R"cpp( class Foo { - int y = 2; Foo(int z) __attribute__((weak)) ; int bar; - int z = 2; };)cpp", "Foo::Foo(int z) __attribute__((weak)) : bar(2){}\n", }, diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize-use-noexcept-error.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize-use-noexcept-error.cpp new file mode 100644 index 00000000000000..9a80b075d65edf --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize-use-noexcept-error.cpp @@ -0,0 +1,6 @@ +// RUN: %check_clang_tidy -expect-clang-tidy-error %s modernize-use-noexcept %t + +// We're not interested in the check issuing a warning here, just making sure +// clang-tidy doesn't assert. +undefined_type doesThrow() throw(); +// CHECK-MESSAGES: :[[@LINE-1]]:1: error: unknown type name 'undefined_type' [clang-diagnostic-error] diff --git a/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp b/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp index 4ebe1237b21cf2..4a0a80146af4be 100644 --- a/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp +++ b/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp @@ -110,6 +110,18 @@ TEST_F(QueryParserTest, Set) { ASSERT_TRUE(isa >(Q)); EXPECT_EQ(&QuerySession::BindRoot, cast >(Q)->Var); EXPECT_EQ(true, cast >(Q)->Value); + + Q = parse("set traversal AsIs"); + ASSERT_TRUE(isa>(Q)); + EXPECT_EQ(&QuerySession::TK, + cast>(Q)->Var); + EXPECT_EQ(ast_type_traits::TK_AsIs, + cast>(Q)->Value); + + Q = parse("set traversal NotATraversal"); + ASSERT_TRUE(isa(Q)); + EXPECT_EQ("expected traversal kind, got 'NotATraversal'", + cast(Q)->ErrStr); } TEST_F(QueryParserTest, Match) { @@ -197,6 +209,11 @@ TEST_F(QueryParserTest, Complete) { EXPECT_EQ("utput ", Comps[0].TypedText); EXPECT_EQ("output", Comps[0].DisplayText); + Comps = QueryParser::complete("set t", 5, QS); + ASSERT_EQ(1u, Comps.size()); + EXPECT_EQ("raversal ", Comps[0].TypedText); + EXPECT_EQ("traversal", Comps[0].DisplayText); + Comps = QueryParser::complete("enable ", 7, QS); ASSERT_EQ(1u, Comps.size()); EXPECT_EQ("output ", Comps[0].TypedText); @@ -214,6 +231,16 @@ TEST_F(QueryParserTest, Complete) { EXPECT_EQ("dump ", Comps[3].TypedText); EXPECT_EQ("dump", Comps[3].DisplayText); + Comps = QueryParser::complete("set traversal ", 14, QS); + ASSERT_EQ(3u, Comps.size()); + + EXPECT_EQ("AsIs ", Comps[0].TypedText); + EXPECT_EQ("AsIs", Comps[0].DisplayText); + EXPECT_EQ("IgnoreImplicitCastsAndParentheses ", Comps[1].TypedText); + EXPECT_EQ("IgnoreImplicitCastsAndParentheses", Comps[1].DisplayText); + EXPECT_EQ("IgnoreUnlessSpelledInSource ", Comps[2].TypedText); + EXPECT_EQ("IgnoreUnlessSpelledInSource", Comps[2].DisplayText); + Comps = QueryParser::complete("match while", 11, QS); ASSERT_EQ(1u, Comps.size()); EXPECT_EQ("Stmt(", Comps[0].TypedText); diff --git a/clang/cmake/caches/CrossWinToARMLinux.cmake b/clang/cmake/caches/CrossWinToARMLinux.cmake index c01c31ae5a7225..3d1e961ada8d0b 100644 --- a/clang/cmake/caches/CrossWinToARMLinux.cmake +++ b/clang/cmake/caches/CrossWinToARMLinux.cmake @@ -89,9 +89,6 @@ set(LIBCXXABI_LINK_TESTS_WITH_SHARED_LIBCXX OFF CACHE BOOL "") set(LIBCXX_LINK_TESTS_WITH_SHARED_LIBCXXABI OFF CACHE BOOL "") set(LIBCXX_LINK_TESTS_WITH_SHARED_LIBCXX OFF CACHE BOOL "") -# FIXME: Remove this when https://reviews.llvm.org/D78200 is merged. -set(LIBCXX_ENABLE_FILESYSTEM OFF CACHE BOOL "") - set(LIBCXX_USE_COMPILER_RT ON CACHE BOOL "") set(LIBCXX_TARGET_TRIPLE "${CMAKE_C_COMPILER_TARGET}" CACHE STRING "") set(LIBCXX_SYSROOT "${DEFAULT_SYSROOT}" CACHE STRING "") diff --git a/clang/docs/CommandGuide/clang.rst b/clang/docs/CommandGuide/clang.rst index 6947450beb43d9..de0e0eda90974d 100644 --- a/clang/docs/CommandGuide/clang.rst +++ b/clang/docs/CommandGuide/clang.rst @@ -246,7 +246,9 @@ Language Selection and Mode Options .. option:: -ffreestanding Indicate that the file should be compiled for a freestanding, not a hosted, - environment. + environment. Note that it is assumed that a freestanding environment will + additionally provide `memcpy`, `memmove`, `memset` and `memcmp` + implementations, as these are needed for efficient codegen for many programs. .. option:: -fno-builtin diff --git a/clang/docs/ConstantInterpreter.rst b/clang/docs/ConstantInterpreter.rst index c976f35a67c576..eba637585b8f06 100644 --- a/clang/docs/ConstantInterpreter.rst +++ b/clang/docs/ConstantInterpreter.rst @@ -13,7 +13,7 @@ clang, improving performance on constructs which are executed inefficiently by the evaluator. The interpreter is activated using the following flags: * ``-fexperimental-new-constant-interpreter`` enables the interpreter, -emitting an error if an unsupported feature is encountered + emitting an error if an unsupported feature is encountered Bytecode Compilation ==================== @@ -130,11 +130,11 @@ descriptor that characterises the entire allocation, along with a few additional attributes: * ``IsStatic`` indicates whether the block has static duration in the -interpreter, i.e. it is not a local in a frame. + interpreter, i.e. it is not a local in a frame. * ``DeclID`` identifies each global declaration (it is set to an invalid -and irrelevant value for locals) in order to prevent illegal writes and -reads involving globals and temporaries with static storage duration. + and irrelevant value for locals) in order to prevent illegal writes and + reads involving globals and temporaries with static storage duration. Static blocks are never deallocated, but local ones might be deallocated even when there are live pointers to them. Pointers are only valid as @@ -150,8 +150,8 @@ The lifetime of blocks is managed through 3 methods stored in the descriptor of the block: * **CtorFn**: initializes the metadata which is store in the block, -alongside actual data. Invokes the default constructors of objects -which are not trivial (``Pointer``, ``RealFP``, etc.) + alongside actual data. Invokes the default constructors of objects + which are not trivial (``Pointer``, ``RealFP``, etc.) * **DtorFn**: invokes the destructors of non-trivial objects. @@ -192,13 +192,13 @@ The interpreter distinguishes 3 different kinds of blocks: has the following fields: * **Offset**: byte offset into the array or record, used to step back to the - parent array or record. + parent array or record. * **IsConst**: flag indicating if the field is const-qualified. * **IsInitialized**: flag indicating whether the field or element was - initialized. For non-primitive fields, this is only relevant to determine - the dynamic type of objects during construction. + initialized. For non-primitive fields, this is only relevant to determine + the dynamic type of objects during construction. * **IsBase**: flag indicating whether the record is a base class. In that - case, the offset can be used to identify the derived class. + case, the offset can be used to identify the derived class. * **IsActive**: indicates if the field is the active field of a union. * **IsMutable**: indicates if the field is marked as mutable. @@ -222,19 +222,19 @@ Pointers, implemented in ``Pointer.h`` are represented as a tagged union. Some of these may not yet be available in upstream ``clang``. * **BlockPointer**: used to reference memory allocated and managed by the - interpreter, being the only pointer kind which allows dereferencing in the - interpreter + interpreter, being the only pointer kind which allows dereferencing in the + interpreter * **ExternPointer**: points to memory which can be addressed, but not read by - the interpreter. It is equivalent to APValue, tracking a declaration and a path - of fields and indices into that allocation. + the interpreter. It is equivalent to APValue, tracking a declaration and a path + of fields and indices into that allocation. * **TargetPointer**: represents a target address derived from a base address - through pointer arithmetic, such as ``((int *)0x100)[20]``. Null pointers are - target pointers with a zero offset. + through pointer arithmetic, such as ``((int *)0x100)[20]``. Null pointers are + target pointers with a zero offset. * **TypeInfoPointer**: tracks information for the opaque type returned by - ``typeid`` + ``typeid`` * **InvalidPointer**: is dummy pointer created by an invalid operation which - allows the interpreter to continue execution. Does not allow pointer - arithmetic or dereferencing. + allows the interpreter to continue execution. Does not allow pointer + arithmetic or dereferencing. Besides the previously mentioned union, a number of other pointer-like types have their own type: @@ -367,17 +367,17 @@ Missing Language Features * ``new`` and ``delete`` * Fixed Point numbers and arithmetic on Complex numbers * Several builtin methods, including string operations and -``__builtin_bit_cast`` + ``__builtin_bit_cast`` * Continue-after-failure: a form of exception handling at the bytecode -level should be implemented to allow execution to resume. As an example, -argument evaluation should resume after the computation of an argument fails. + level should be implemented to allow execution to resume. As an example, + argument evaluation should resume after the computation of an argument fails. * Pointer-to-Integer conversions * Lazy descriptors: the interpreter creates a ``Record`` and ``Descriptor`` -when it encounters a type: ones which are not yet defined should be lazily -created when required + when it encounters a type: ones which are not yet defined should be lazily + created when required Known Bugs ---------- * If execution fails, memory storing APInts and APFloats is leaked when the -stack is cleared + stack is cleared diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 16f5915856fdb7..8f9dc81ec0b304 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -82,6 +82,10 @@ Non-comprehensive list of changes in this release linker. If the user links the program with the ``clang`` or ``clang-cl`` drivers, the driver will pass this flag for them. +- Clang's profile files generated through ``-fprofile-instr-generate`` are using + a fixed hashing algorithm that prevents some collision when loading + out-of-date profile informations. Clang can still read old profile files. + New Compiler Flags ------------------ @@ -246,7 +250,44 @@ release of Clang. Users of the build system should adjust accordingly. AST Matchers ------------ -- ... +- Traversal in AST Matchers was simplified to use the + ``TK_IgnoreUnlessSpelledInSource`` mode by default, instead of ``TK_AsIs``. + This means that many uses of the ``ignoringImplicit()`` and similar matchers + is no longer necessary. Clients of AST Matchers which wish to match on + implicit AST nodes can wrap their matcher in ``traverse(TK_AsIs, ...)`` or + use ``TraversalKindScope`` if appropriate. The ``clang-query`` tool also + uses ``IgnoreUnlessSpelledInSource`` by default. The mode can be changed + using ``set traversal AsIs`` in the ``clang-query`` environment. + + As this change requires downstream tools which use AST Matchers to adapt + to the new default, a porting guide may be useful for downstream tools + needing to adapt. + + Note that although there are many steps below, only the first is + non-optional. The steps are intentionally extemely granular to facilitate + understanding of the guide itself. It is reasonable to do some of the + steps at the same time if you understand the guide: + + 1. Use ``(your ASTContext instance).getParentMapContext().setTraversalKind(TK_AsIs)`` + to restore the previous behavior for your tool. All further steps in + this porting guide are optional. + 2. Wrap your existing matcher expressions with ``traverse(TK_AsIs, ...)`` + before passing them to ``ASTMatchFinder::addMatcher``. + 3. Remove ``(your ASTContext instance).getParentMapContext().setTraversalKind(TK_AsIs)`` + from your tool so that the default behavior of your tool matches the + default behavior of upstream clang. This is made possible by wrapping + your matchers in ``traverse(TK_AsIs, ...)`` from step (2). + 4. Audit your matcher expressions and remove ``traverse(TK_AsIs, ...)`` + where not needed. + 5. Audit your matcher expressions and remove calls to ``ignoring*()`` + matchers where not needed. + 6. Audit your matcher expressions and consider whether the matcher is + better using the ``TK_AsIs`` mode or if it can be better expressed in + the default mode. For example, some matchers explicitly match + ``has(implicitCastExpr(has(...)))``. Such matchers are sometimes + written by author who were unaware of the existence of the + ``ignoring*()`` matchers. + clang-format ------------ diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index 0bfb6456dc820b..dcf1f28994de42 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -1374,6 +1374,34 @@ double freed, or use after freed. This check attempts to find such problems. zx_handle_close(sb); } +WebKit +^^^^^^ + +WebKit is an open-source web browser engine available for macOS, iOS and Linux. +This section describes checkers that can find issues in WebKit codebase. + +Most of the checkers focus on memory management for which WebKit uses custom implementation of reference counted smartpointers. +Checker are formulated in terms related to ref-counting: +* *Ref-counted type* is either ``Ref`` or ``RefPtr``. +* *Ref-countable type* is any type that implements ``ref()`` and ``deref()`` methods as ``RefPtr<>`` is a template (i. e. relies on duck typing). +* *Uncounted type* is ref-countable but not ref-counted type. + +.. _webkit-RefCntblBaseVirtualDtor: + +webkit.RefCntblBaseVirtualDtor +"""""""""""""""""""""""""""""""""""" +All uncounted types used as base classes must have a virtual destructor. + +Ref-counted types hold their ref-countable data by a raw pointer and allow implicit upcasting from ref-counted pointer to derived type to ref-counted pointer to base type. This might lead to an object of (dynamic) derived type being deleted via pointer to the base class type which C++ standard defines as UB in case the base class doesn't have virtual destructor ``[expr.delete]``. + +.. code-block:: cpp + + struct RefCntblBase { + void ref() {} + void deref() {} + }; + + struct Derived : RefCntblBase { }; // warn .. _alpha-checkers: diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index d7136a4cd420b1..2e1630827cce31 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -2125,19 +2125,17 @@ class FunctionDecl : public DeclaratorDecl, bool isTrivialForCall() const { return FunctionDeclBits.IsTrivialForCall; } void setTrivialForCall(bool IT) { FunctionDeclBits.IsTrivialForCall = IT; } - /// Whether this function is defaulted per C++0x. Only valid for - /// special member functions. + /// Whether this function is defaulted. Valid for e.g. + /// special member functions, defaulted comparisions (not methods!). bool isDefaulted() const { return FunctionDeclBits.IsDefaulted; } void setDefaulted(bool D = true) { FunctionDeclBits.IsDefaulted = D; } - /// Whether this function is explicitly defaulted per C++0x. Only valid - /// for special member functions. + /// Whether this function is explicitly defaulted. bool isExplicitlyDefaulted() const { return FunctionDeclBits.IsExplicitlyDefaulted; } - /// State that this function is explicitly defaulted per C++0x. Only valid - /// for special member functions. + /// State that this function is explicitly defaulted. void setExplicitlyDefaulted(bool ED = true) { FunctionDeclBits.IsExplicitlyDefaulted = ED; } diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index 54e83f4619800e..91e4d011a3e969 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -6597,6 +6597,110 @@ class OMPUseDevicePtrClause final } }; +/// This represents clause 'use_device_addr' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp target data use_device_addr(a,b) +/// \endcode +/// In this example directive '#pragma omp target data' has clause +/// 'use_device_addr' with the variables 'a' and 'b'. +class OMPUseDeviceAddrClause final + : public OMPMappableExprListClause, + private llvm::TrailingObjects< + OMPUseDeviceAddrClause, Expr *, ValueDecl *, unsigned, + OMPClauseMappableExprCommon::MappableComponent> { + friend class OMPClauseReader; + friend OMPMappableExprListClause; + friend OMPVarListClause; + friend TrailingObjects; + + /// Build clause with number of variables \a NumVars. + /// + /// \param Locs Locations needed to build a mappable clause. It includes 1) + /// StartLoc: starting location of the clause (the clause keyword); 2) + /// LParenLoc: location of '('; 3) EndLoc: ending location of the clause. + /// \param Sizes All required sizes to build a mappable clause. It includes 1) + /// NumVars: number of expressions listed in this clause; 2) + /// NumUniqueDeclarations: number of unique base declarations in this clause; + /// 3) NumComponentLists: number of component lists in this clause; and 4) + /// NumComponents: total number of expression components in the clause. + explicit OMPUseDeviceAddrClause(const OMPVarListLocTy &Locs, + const OMPMappableExprListSizeTy &Sizes) + : OMPMappableExprListClause(llvm::omp::OMPC_use_device_addr, Locs, + Sizes) {} + + /// Build an empty clause. + /// + /// \param Sizes All required sizes to build a mappable clause. It includes 1) + /// NumVars: number of expressions listed in this clause; 2) + /// NumUniqueDeclarations: number of unique base declarations in this clause; + /// 3) NumComponentLists: number of component lists in this clause; and 4) + /// NumComponents: total number of expression components in the clause. + explicit OMPUseDeviceAddrClause(const OMPMappableExprListSizeTy &Sizes) + : OMPMappableExprListClause(llvm::omp::OMPC_use_device_addr, + OMPVarListLocTy(), Sizes) {} + + /// Define the sizes of each trailing object array except the last one. This + /// is required for TrailingObjects to work properly. + size_t numTrailingObjects(OverloadToken) const { + return varlist_size(); + } + size_t numTrailingObjects(OverloadToken) const { + return getUniqueDeclarationsNum(); + } + size_t numTrailingObjects(OverloadToken) const { + return getUniqueDeclarationsNum() + getTotalComponentListNum(); + } + +public: + /// Creates clause with a list of variables \a Vars. + /// + /// \param C AST context. + /// \param Locs Locations needed to build a mappable clause. It includes 1) + /// StartLoc: starting location of the clause (the clause keyword); 2) + /// LParenLoc: location of '('; 3) EndLoc: ending location of the clause. + /// \param Vars The original expression used in the clause. + /// \param Declarations Declarations used in the clause. + /// \param ComponentLists Component lists used in the clause. + static OMPUseDeviceAddrClause * + Create(const ASTContext &C, const OMPVarListLocTy &Locs, + ArrayRef Vars, ArrayRef Declarations, + MappableExprComponentListsRef ComponentLists); + + /// Creates an empty clause with the place for \a NumVars variables. + /// + /// \param C AST context. + /// \param Sizes All required sizes to build a mappable clause. It includes 1) + /// NumVars: number of expressions listed in this clause; 2) + /// NumUniqueDeclarations: number of unique base declarations in this clause; + /// 3) NumComponentLists: number of component lists in this clause; and 4) + /// NumComponents: total number of expression components in the clause. + static OMPUseDeviceAddrClause * + CreateEmpty(const ASTContext &C, const OMPMappableExprListSizeTy &Sizes); + + child_range children() { + return child_range(reinterpret_cast(varlist_begin()), + reinterpret_cast(varlist_end())); + } + + const_child_range children() const { + auto Children = const_cast(this)->children(); + return const_child_range(Children.begin(), Children.end()); + } + + child_range used_children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range used_children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == llvm::omp::OMPC_use_device_addr; + } +}; + /// This represents clause 'is_device_ptr' in the '#pragma omp ...' /// directives. /// diff --git a/clang/include/clang/AST/ParentMapContext.h b/clang/include/clang/AST/ParentMapContext.h index be4d75df7b9990..5f9936b28e8fba 100644 --- a/clang/include/clang/AST/ParentMapContext.h +++ b/clang/include/clang/AST/ParentMapContext.h @@ -67,7 +67,7 @@ class ParentMapContext { private: ASTContext &ASTCtx; class ParentMap; - TraversalKind Traversal = TK_AsIs; + TraversalKind Traversal = TK_IgnoreUnlessSpelledInSource; std::unique_ptr Parents; }; diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index a264d1cf24b235..83ff49e405020d 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2103,11 +2103,11 @@ bool RecursiveASTVisitor::TraverseFunctionHelper(FunctionDecl *D) { } } - bool VisitBody = D->isThisDeclarationADefinition(); - // If a method is set to default outside the class definition the compiler - // generates the method body and adds it to the AST. - if (const auto *MD = dyn_cast(D)) - VisitBody &= !MD->isDefaulted() || getDerived().shouldVisitImplicitCode(); + bool VisitBody = + D->isThisDeclarationADefinition() && + // Don't visit the function body if the function definition is generated + // by clang. + (!D->isDefaulted() || getDerived().shouldVisitImplicitCode()); if (VisitBody) { TRY_TO(TraverseStmt(D->getBody())); // Function body. @@ -3521,6 +3521,13 @@ bool RecursiveASTVisitor::VisitOMPUseDevicePtrClause( return true; } +template +bool RecursiveASTVisitor::VisitOMPUseDeviceAddrClause( + OMPUseDeviceAddrClause *C) { + TRY_TO(VisitOMPClauseList(C)); + return true; +} + template bool RecursiveASTVisitor::VisitOMPIsDevicePtrClause( OMPIsDevicePtrClause *C) { diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 21b14de997cbbe..ed31dea925f395 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1064,6 +1064,21 @@ class QualType { /// Return the address space of this type. inline LangAS getAddressSpace() const; + /// Returns true if address space qualifiers overlap with T address space + /// qualifiers. + /// OpenCL C defines conversion rules for pointers to different address spaces + /// and notion of overlapping address spaces. + /// CL1.1 or CL1.2: + /// address spaces overlap iff they are they same. + /// OpenCL C v2.0 s6.5.5 adds: + /// __generic overlaps with any address space except for __constant. + bool isAddressSpaceOverlapping(QualType T) const { + Qualifiers Q = getQualifiers(); + Qualifiers TQ = T.getQualifiers(); + // Address spaces overlap if at least one of them is a superset of another + return Q.isAddressSpaceSupersetOf(TQ) || TQ.isAddressSpaceSupersetOf(Q); + } + /// Returns gc attribute of this type. inline Qualifiers::GC getObjCGCAttr() const; @@ -2631,22 +2646,6 @@ class PointerType : public Type, public llvm::FoldingSetNode { public: QualType getPointeeType() const { return PointeeType; } - /// Returns true if address spaces of pointers overlap. - /// OpenCL v2.0 defines conversion rules for pointers to different - /// address spaces (OpenCLC v2.0 s6.5.5) and notion of overlapping - /// address spaces. - /// CL1.1 or CL1.2: - /// address spaces overlap iff they are they same. - /// CL2.0 adds: - /// __generic overlaps with any address space except for __constant. - bool isAddressSpaceOverlapping(const PointerType &other) const { - Qualifiers thisQuals = PointeeType.getQualifiers(); - Qualifiers otherQuals = other.getPointeeType().getQualifiers(); - // Address spaces overlap if at least one of them is a superset of another - return thisQuals.isAddressSpaceSupersetOf(otherQuals) || - otherQuals.isAddressSpaceSupersetOf(thisQuals); - } - bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 460962d9e73b60..a750747c9aa3f7 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -2662,7 +2662,7 @@ AST_MATCHER_P(UnaryExprOrTypeTraitExpr, ofKind, UnaryExprOrTypeTrait, Kind) { /// Same as unaryExprOrTypeTraitExpr, but only matching /// alignof. -inline internal::Matcher alignOfExpr( +inline internal::BindableMatcher alignOfExpr( const internal::Matcher &InnerMatcher) { return stmt(unaryExprOrTypeTraitExpr( allOf(anyOf(ofKind(UETT_AlignOf), ofKind(UETT_PreferredAlignOf)), @@ -2671,7 +2671,7 @@ inline internal::Matcher alignOfExpr( /// Same as unaryExprOrTypeTraitExpr, but only matching /// sizeof. -inline internal::Matcher sizeOfExpr( +inline internal::BindableMatcher sizeOfExpr( const internal::Matcher &InnerMatcher) { return stmt(unaryExprOrTypeTraitExpr( allOf(ofKind(UETT_SizeOf), InnerMatcher))); diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 833b862cfb5f53..a691e2332ff7ad 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1275,6 +1275,11 @@ def FallThrough : StmtAttr { let Documentation = [FallthroughDocs]; } +def NoMerge : StmtAttr { + let Spellings = [Clang<"nomerge">]; + let Documentation = [NoMergeDocs]; +} + def FastCall : DeclOrTypeAttr { let Spellings = [GCC<"fastcall">, Keyword<"__fastcall">, Keyword<"_fastcall">]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index e3308cd7487409..5222c92c42a0e0 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -350,6 +350,20 @@ that appears to be capable of returning to its caller. }]; } +def NoMergeDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +If a statement is marked ``nomerge`` and contains call experessions, those call +expressions inside the statement will not be merged during optimization. This +attribute can be used to prevent the optimizer from obscuring the source +location of certain calls. For example, it will prevent tail merging otherwise +identical code sequences that raise an exception or terminate the program. Tail +merging normally reduces the precision of source location information, making +stack traces less useful for debugging. This attribute gives the user control +over the tradeoff between code size and debug information precision. + }]; +} + def AssertCapabilityDocs : Documentation { let Category = DocCatFunction; let Heading = "assert_capability, assert_shared_capability"; diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def index 4f1a7f24c4329c..4c43d63ffec403 100644 --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/include/clang/Basic/Builtins.def @@ -323,6 +323,9 @@ BUILTIN(__builtin_truncf, "ff", "Fnc") BUILTIN(__builtin_truncl, "LdLd", "Fnc") BUILTIN(__builtin_truncf16, "hh", "Fnc") +// Access to floating point environment +BUILTIN(__builtin_flt_rounds, "i", "n") + // C99 complex builtins BUILTIN(__builtin_cabs, "dXd", "Fne") BUILTIN(__builtin_cabsf, "fXf", "Fne") @@ -517,7 +520,6 @@ BUILTIN(__builtin_return_address, "v*IUi", "n") BUILTIN(__builtin_extract_return_addr, "v*v*", "n") BUILTIN(__builtin_frame_address, "v*IUi", "n") BUILTIN(__builtin___clear_cache, "vc*c*", "n") -BUILTIN(__builtin_flt_rounds, "i", "nc") BUILTIN(__builtin_setjmp, "iv**", "j") BUILTIN(__builtin_longjmp, "vv**i", "r") BUILTIN(__builtin_unwind_init, "v", "") diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index fdca8532ab53e5..d010a7dfb2de93 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -358,9 +358,6 @@ def err_analyzer_checker_option_invalid_input : Error< "invalid input for checker option '%0', that expects %1">; def err_analyzer_checker_incompatible_analyzer_option : Error< "checker cannot be enabled with analyzer option '%0' == %1">; -def err_analyzer_missing_output_loc : Error< - "analyzer output type '%0' requires an output %1 to be specified with " - "-o ">; def err_drv_invalid_hvx_length : Error< "-mhvx-length is not supported without a -mhvx/-mhvx= flag">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index d415802916b6cc..845e329033c39a 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2762,6 +2762,10 @@ def warn_auto_var_is_id : Warning< InGroup>; // Attributes +def warn_nomerge_attribute_ignored_in_stmt: Warning< + "%0 attribute is ignored because there exists no call expression inside the " + "statement">, + InGroup; def err_nsobject_attribute : Error< "'NSObject' attribute is for pointer types only">; def err_attributes_are_not_compatible : Error< diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index e94305da46ba52..6e72b47f489b5f 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -301,6 +301,7 @@ ENUM_LANGOPT(TypeVisibilityMode, Visibility, 3, DefaultVisibility, LANGOPT(SetVisibilityForExternDecls, 1, 0, "apply global symbol visibility to external declarations without an explicit visibility") BENIGN_LANGOPT(SemanticInterposition , 1, 0, "semantic interposition") +BENIGN_LANGOPT(ExplicitNoSemanticInterposition, 1, 0, "explicitly no semantic interposition") ENUM_LANGOPT(StackProtector, StackProtectorMode, 2, SSPOff, "stack protector mode") ENUM_LANGOPT(TrivialAutoVarInit, TrivialAutoVarInitKind, 2, TrivialAutoVarInitKind::Uninitialized, diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h index e6c2cb39566cee..2c80dd4fa81036 100644 --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -365,6 +365,20 @@ namespace clang { }; llvm::StringRef getParameterABISpelling(ParameterABI kind); + + inline llvm::StringRef getAccessSpelling(AccessSpecifier AS) { + switch (AS) { + case AccessSpecifier::AS_public: + return "public"; + case AccessSpecifier::AS_protected: + return "protected"; + case AccessSpecifier::AS_private: + return "private"; + case AccessSpecifier::AS_none: + return {}; + } + llvm_unreachable("Unknown AccessSpecifier"); + } } // end namespace clang #endif // LLVM_CLANG_BASIC_SPECIFIERS_H diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 7213af1731c173..e88e6cf8a13017 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3371,7 +3371,7 @@ defm ipa_cp : BooleanFFlag<"ipa-cp">, Group; defm ivopts : BooleanFFlag<"ivopts">, Group; def fsemantic_interposition : Flag<["-"], "fsemantic-interposition">, Group, Flags<[CC1Option]>; -def fno_semantic_interposition: Flag<["-"], "fno-semantic-interposition">, Group; +def fno_semantic_interposition: Flag<["-"], "fno-semantic-interposition">, Group, Flags<[CC1Option]>; defm non_call_exceptions : BooleanFFlag<"non-call-exceptions">, Group; defm peel_loops : BooleanFFlag<"peel-loops">, Group; defm permissive : BooleanFFlag<"permissive">, Group; diff --git a/clang/include/clang/Index/IndexingAction.h b/clang/include/clang/Index/IndexingAction.h index 9ed2a018f1617d..4baa2d5e72603c 100644 --- a/clang/include/clang/Index/IndexingAction.h +++ b/clang/include/clang/Index/IndexingAction.h @@ -30,22 +30,21 @@ namespace serialization { } namespace index { - class IndexDataConsumer; +class IndexDataConsumer; /// Creates an ASTConsumer that indexes all symbols (macros and AST decls). +std::unique_ptr +createIndexingASTConsumer(std::shared_ptr DataConsumer, + const IndexingOptions &Opts, + std::shared_ptr PP); + std::unique_ptr createIndexingASTConsumer( std::shared_ptr DataConsumer, const IndexingOptions &Opts, std::shared_ptr PP, + // Prefer to set Opts.ShouldTraverseDecl and use the above overload. + // This version is only needed if used to *track* function body parsing. std::function ShouldSkipFunctionBody); -inline std::unique_ptr createIndexingASTConsumer( - std::shared_ptr DataConsumer, - const IndexingOptions &Opts, std::shared_ptr PP) { - return createIndexingASTConsumer( - std::move(DataConsumer), Opts, std::move(PP), - /*ShouldSkipFunctionBody=*/[](const Decl *) { return false; }); -} - /// Creates a frontend action that indexes all symbols (macros and AST decls). std::unique_ptr createIndexingAction(std::shared_ptr DataConsumer, diff --git a/clang/include/clang/Index/IndexingOptions.h b/clang/include/clang/Index/IndexingOptions.h index bbfd6e4a72c621..9f5c03d1b3b948 100644 --- a/clang/include/clang/Index/IndexingOptions.h +++ b/clang/include/clang/Index/IndexingOptions.h @@ -14,6 +14,7 @@ #include namespace clang { +class Decl; namespace index { struct IndexingOptions { @@ -34,6 +35,12 @@ struct IndexingOptions { // Has no effect if IndexFunctionLocals are false. bool IndexParametersInDeclarations = false; bool IndexTemplateParameters = false; + + // If set, skip indexing inside some declarations for performance. + // This prevents traversal, so skipping a struct means its declaration an + // members won't be indexed, but references elsewhere to that struct will be. + // Currently this is only checked for top-level declarations. + std::function ShouldTraverseDecl; }; } // namespace index diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 9276852543068f..e63f65e2580cce 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10776,6 +10776,9 @@ class Sema final { /// Called on well-formed 'use_device_ptr' clause. OMPClause *ActOnOpenMPUseDevicePtrClause(ArrayRef VarList, const OMPVarListLocTy &Locs); + /// Called on well-formed 'use_device_addr' clause. + OMPClause *ActOnOpenMPUseDeviceAddrClause(ArrayRef VarList, + const OMPVarListLocTy &Locs); /// Called on well-formed 'is_device_ptr' clause. OMPClause *ActOnOpenMPIsDevicePtrClause(ArrayRef VarList, const OMPVarListLocTy &Locs); diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 93c4d964d77240..2ba3881c613517 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -116,6 +116,9 @@ def NonDeterminismAlpha : Package<"nondeterminism">, ParentPackage; def Fuchsia : Package<"fuchsia">; def FuchsiaAlpha : Package<"fuchsia">, ParentPackage; +def WebKit : Package<"webkit">; +def WebKitAlpha : Package<"webkit">, ParentPackage; + //===----------------------------------------------------------------------===// // Core Checkers. //===----------------------------------------------------------------------===// @@ -553,13 +556,13 @@ def NewDeleteChecker : Checker<"NewDelete">, def NewDeleteLeaksChecker : Checker<"NewDeleteLeaks">, HelpText<"Check for memory leaks. Traces memory managed by new/delete.">, - Dependencies<[NewDeleteChecker]>, + Dependencies<[DynamicMemoryModeling]>, Documentation; def PlacementNewChecker : Checker<"PlacementNew">, HelpText<"Check if default placement new is provided with pointers to " "sufficient storage capacity">, - Dependencies<[NewDeleteChecker]>, + Dependencies<[DynamicMemoryModeling]>, Documentation; def CXXSelfAssignmentChecker : Checker<"SelfAssignment">, @@ -1091,15 +1094,6 @@ def NSErrorChecker : Checker<"NSError">, def RetainCountChecker : Checker<"RetainCount">, HelpText<"Check for leaks and improper reference count management">, CheckerOptions<[ - CmdLineOption, CmdLineOption, } // end fuchsia +//===----------------------------------------------------------------------===// +// WebKit checkers. +//===----------------------------------------------------------------------===// + +let ParentPackage = WebKit in { + +def RefCntblBaseVirtualDtorChecker : Checker<"RefCntblBaseVirtualDtor">, + HelpText<"Check for any ref-countable base class having virtual destructor.">, + Documentation; +} // end webkit diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index 373caa30bbc9f9..d2df24a6e21b7e 100644 --- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -206,7 +206,7 @@ class AnalyzerOptions : public RefCountedBase { ConfigTable Config; AnalysisStores AnalysisStoreOpt = RegionStoreModel; AnalysisConstraints AnalysisConstraintsOpt = RangeConstraintsModel; - AnalysisDiagClients AnalysisDiagOpt = PD_TEXT_MINIMAL; + AnalysisDiagClients AnalysisDiagOpt = PD_HTML; AnalysisPurgeMode AnalysisPurgeOpt = PurgeStmt; std::string AnalyzeSpecificFunction; diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h index 935b2bb7b937d3..335536b6a31068 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -32,7 +32,7 @@ namespace clang { namespace ento { class ProgramStateManager; -class SubEngine; +class ExprEngine; class SymbolReaper; class ConditionTruthVal { @@ -193,10 +193,11 @@ class ConstraintManager { std::unique_ptr CreateRangeConstraintManager(ProgramStateManager &statemgr, - SubEngine *subengine); + ExprEngine *exprengine); std::unique_ptr -CreateZ3ConstraintManager(ProgramStateManager &statemgr, SubEngine *subengine); +CreateZ3ConstraintManager(ProgramStateManager &statemgr, + ExprEngine *exprengine); } // namespace ento } // namespace clang diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h index 278193ef99edea..2aca2c99ef4fdc 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h @@ -41,7 +41,7 @@ class LabelDecl; namespace ento { class FunctionSummariesTy; -class SubEngine; +class ExprEngine; //===----------------------------------------------------------------------===// /// CoreEngine - Implements the core logic of the graph-reachability @@ -69,7 +69,7 @@ class CoreEngine { std::vector>; private: - SubEngine &SubEng; + ExprEngine &ExprEng; /// G - The simulation graph. Each node is a (location,state) pair. mutable ExplodedGraph G; @@ -129,7 +129,7 @@ class CoreEngine { public: /// Construct a CoreEngine object to analyze the provided CFG. - CoreEngine(SubEngine &subengine, + CoreEngine(ExprEngine &exprengine, FunctionSummariesTy *FS, AnalyzerOptions &Opts); diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index c66c54116a0c6a..3611979c619113 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -21,6 +21,7 @@ #include "clang/Analysis/DomainSpecific/ObjCNoReturn.h" #include "clang/Analysis/ProgramPoint.h" #include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" @@ -29,9 +30,9 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h" #include "llvm/ADT/ArrayRef.h" #include @@ -42,6 +43,8 @@ namespace clang { class AnalysisDeclContextManager; class AnalyzerOptions; class ASTContext; +class CFGBlock; +class CFGElement; class ConstructionContext; class CXXBindTemporaryExpr; class CXXCatchStmt; @@ -72,16 +75,29 @@ class CrossTranslationUnitContext; namespace ento { +class AnalysisManager; class BasicValueFactory; +class BlockCounter; +class BranchNodeBuilder; class CallEvent; class CheckerManager; class ConstraintManager; class CXXTempObjectRegion; +class EndOfFunctionNodeBuilder; +class ExplodedNodeSet; +class ExplodedNode; +class IndirectGotoNodeBuilder; class MemRegion; +struct NodeBuilderContext; +class NodeBuilderWithSinks; +class ProgramState; +class ProgramStateManager; class RegionAndSymbolInvalidationTraits; class SymbolManager; +class SwitchNodeBuilder; -class ExprEngine : public SubEngine { +class ExprEngine { + void anchor(); public: /// The modes of inlining, which override the default analysis-wide settings. enum InliningModes { @@ -161,7 +177,7 @@ class ExprEngine : public SubEngine { SetOfConstDecls *VisitedCalleesIn, FunctionSummariesTy *FS, InliningModes HowToInlineIn); - ~ExprEngine() override = default; + virtual ~ExprEngine() = default; /// Returns true if there is still simulation state on the worklist. bool ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) { @@ -181,7 +197,7 @@ class ExprEngine : public SubEngine { /// getContext - Return the ASTContext associated with this analysis. ASTContext &getContext() const { return AMgr.getASTContext(); } - AnalysisManager &getAnalysisManager() override { return AMgr; } + AnalysisManager &getAnalysisManager() { return AMgr; } AnalysisDeclContextManager &getAnalysisDeclContextManager() { return AMgr.getAnalysisDeclContextManager(); @@ -196,7 +212,7 @@ class ExprEngine : public SubEngine { BugReporter &getBugReporter() { return BR; } cross_tu::CrossTranslationUnitContext * - getCrossTranslationUnitContext() override { + getCrossTranslationUnitContext() { return &CTU; } @@ -232,7 +248,7 @@ class ExprEngine : public SubEngine { /// getInitialState - Return the initial state used for the root vertex /// in the ExplodedGraph. - ProgramStateRef getInitialState(const LocationContext *InitLoc) override; + ProgramStateRef getInitialState(const LocationContext *InitLoc); ExplodedGraph &getGraph() { return G; } const ExplodedGraph &getGraph() const { return G; } @@ -270,7 +286,7 @@ class ExprEngine : public SubEngine { /// processCFGElement - Called by CoreEngine. Used to generate new successor /// nodes by processing the 'effects' of a CFG element. void processCFGElement(const CFGElement E, ExplodedNode *Pred, - unsigned StmtIdx, NodeBuilderContext *Ctx) override; + unsigned StmtIdx, NodeBuilderContext *Ctx); void ProcessStmt(const Stmt *S, ExplodedNode *Pred); @@ -296,7 +312,7 @@ class ExprEngine : public SubEngine { /// Called by CoreEngine when processing the entrance of a CFGBlock. void processCFGBlockEntrance(const BlockEdge &L, NodeBuilderWithSinks &nodeBuilder, - ExplodedNode *Pred) override; + ExplodedNode *Pred); /// ProcessBranch - Called by CoreEngine. Used to generate successor /// nodes by processing the 'effects' of a branch condition. @@ -305,7 +321,7 @@ class ExprEngine : public SubEngine { ExplodedNode *Pred, ExplodedNodeSet &Dst, const CFGBlock *DstT, - const CFGBlock *DstF) override; + const CFGBlock *DstF); /// Called by CoreEngine. /// Used to generate successor nodes for temporary destructors depending @@ -314,7 +330,7 @@ class ExprEngine : public SubEngine { NodeBuilderContext &BldCtx, ExplodedNode *Pred, ExplodedNodeSet &Dst, const CFGBlock *DstT, - const CFGBlock *DstF) override; + const CFGBlock *DstF); /// Called by CoreEngine. Used to processing branching behavior /// at static initializers. @@ -323,27 +339,27 @@ class ExprEngine : public SubEngine { ExplodedNode *Pred, ExplodedNodeSet &Dst, const CFGBlock *DstT, - const CFGBlock *DstF) override; + const CFGBlock *DstF); /// processIndirectGoto - Called by CoreEngine. Used to generate successor /// nodes by processing the 'effects' of a computed goto jump. - void processIndirectGoto(IndirectGotoNodeBuilder& builder) override; + void processIndirectGoto(IndirectGotoNodeBuilder& builder); /// ProcessSwitch - Called by CoreEngine. Used to generate successor /// nodes by processing the 'effects' of a switch statement. - void processSwitch(SwitchNodeBuilder& builder) override; + void processSwitch(SwitchNodeBuilder& builder); /// Called by CoreEngine. Used to notify checkers that processing a /// function has begun. Called for both inlined and and top-level functions. void processBeginOfFunction(NodeBuilderContext &BC, ExplodedNode *Pred, ExplodedNodeSet &Dst, - const BlockEdge &L) override; + const BlockEdge &L); /// Called by CoreEngine. Used to notify checkers that processing a /// function has ended. Called for both inlined and and top-level functions. void processEndOfFunction(NodeBuilderContext& BC, ExplodedNode *Pred, - const ReturnStmt *RS = nullptr) override; + const ReturnStmt *RS = nullptr); /// Remove dead bindings/symbols before exiting a function. void removeDeadOnEndOfFunction(NodeBuilderContext& BC, @@ -352,19 +368,19 @@ class ExprEngine : public SubEngine { /// Generate the entry node of the callee. void processCallEnter(NodeBuilderContext& BC, CallEnter CE, - ExplodedNode *Pred) override; + ExplodedNode *Pred); /// Generate the sequence of nodes that simulate the call exit and the post /// visit for CallExpr. - void processCallExit(ExplodedNode *Pred) override; + void processCallExit(ExplodedNode *Pred); /// Called by CoreEngine when the analysis worklist has terminated. - void processEndWorklist() override; + void processEndWorklist(); /// evalAssume - Callback function invoked by the ConstraintManager when /// making assumptions about state values. ProgramStateRef processAssume(ProgramStateRef state, SVal cond, - bool assumption) override; + bool assumption); /// processRegionChanges - Called by ProgramStateManager whenever a change is made /// to the store. Used to update checkers that track region values. @@ -374,14 +390,21 @@ class ExprEngine : public SubEngine { ArrayRef ExplicitRegions, ArrayRef Regions, const LocationContext *LCtx, - const CallEvent *Call) override; + const CallEvent *Call); + + inline ProgramStateRef + processRegionChange(ProgramStateRef state, + const MemRegion* MR, + const LocationContext *LCtx) { + return processRegionChanges(state, nullptr, MR, MR, LCtx, nullptr); + } /// printJson - Called by ProgramStateManager to print checker-specific data. void printJson(raw_ostream &Out, ProgramStateRef State, const LocationContext *LCtx, const char *NL, - unsigned int Space, bool IsDot) const override; + unsigned int Space, bool IsDot) const; - ProgramStateManager &getStateManager() override { return StateMgr; } + ProgramStateManager &getStateManager() { return StateMgr; } StoreManager &getStoreManager() { return StateMgr.getStoreManager(); } @@ -608,23 +631,11 @@ class ExprEngine : public SubEngine { const ConstructionContextItem &Item, const LocationContext *LC); -protected: - /// evalBind - Handle the semantics of binding a value to a specific location. - /// This method is used by evalStore, VisitDeclStmt, and others. - void evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNode *Pred, - SVal location, SVal Val, bool atDeclInit = false, - const ProgramPoint *PP = nullptr); - /// Call PointerEscape callback when a value escapes as a result of bind. ProgramStateRef processPointerEscapedOnBind( ProgramStateRef State, ArrayRef> LocAndVals, const LocationContext *LCtx, PointerEscapeKind Kind, - const CallEvent *Call) override; - - ProgramStateRef - processPointerEscapedOnBind(ProgramStateRef State, - SVal Loc, SVal Val, - const LocationContext *LCtx); + const CallEvent *Call); /// Call PointerEscape callback when a value escapes as a result of /// region invalidation. @@ -634,7 +645,19 @@ class ExprEngine : public SubEngine { const InvalidatedSymbols *Invalidated, ArrayRef ExplicitRegions, const CallEvent *Call, - RegionAndSymbolInvalidationTraits &ITraits) override; + RegionAndSymbolInvalidationTraits &ITraits); + +private: + /// evalBind - Handle the semantics of binding a value to a specific location. + /// This method is used by evalStore, VisitDeclStmt, and others. + void evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNode *Pred, + SVal location, SVal Val, bool atDeclInit = false, + const ProgramPoint *PP = nullptr); + + ProgramStateRef + processPointerEscapedOnBind(ProgramStateRef State, + SVal Loc, SVal Val, + const LocationContext *LCtx); /// A simple wrapper when you only need to notify checkers of pointer-escape /// of some values. diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h index ecb61bffe3d95a..a0d7db6dd860c6 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h @@ -39,7 +39,7 @@ class CallEvent; class CallEventManager; typedef std::unique_ptr(*ConstraintManagerCreator)( - ProgramStateManager &, SubEngine *); + ProgramStateManager &, ExprEngine *); typedef std::unique_ptr(*StoreManagerCreator)( ProgramStateManager &); @@ -460,8 +460,8 @@ class ProgramStateManager { friend class ProgramState; friend void ProgramStateRelease(const ProgramState *state); private: - /// Eng - The SubEngine that owns this state manager. - SubEngine *Eng; /* Can be null. */ + /// Eng - The ExprEngine that owns this state manager. + ExprEngine *Eng; /* Can be null. */ EnvironmentManager EnvMgr; std::unique_ptr StoreMgr; @@ -493,7 +493,7 @@ class ProgramStateManager { StoreManagerCreator CreateStoreManager, ConstraintManagerCreator CreateConstraintManager, llvm::BumpPtrAllocator& alloc, - SubEngine *subeng); + ExprEngine *expreng); ~ProgramStateManager(); @@ -534,7 +534,7 @@ class ProgramStateManager { StoreManager &getStoreManager() { return *StoreMgr; } ConstraintManager &getConstraintManager() { return *ConstraintMgr; } - SubEngine &getOwningEngine() { return *Eng; } + ExprEngine &getOwningEngine() { return *Eng; } ProgramStateRef removeDeadBindingsFromEnvironmentAndStore(ProgramStateRef St, diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h index a9ca3451d8f3e9..c72f8292647dc9 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h @@ -137,8 +137,8 @@ struct ProgramStateTrait class RangedConstraintManager : public SimpleConstraintManager { public: - RangedConstraintManager(SubEngine *SE, SValBuilder &SB) - : SimpleConstraintManager(SE, SB) {} + RangedConstraintManager(ExprEngine *EE, SValBuilder &SB) + : SimpleConstraintManager(EE, SB) {} ~RangedConstraintManager() override; diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h index 294a45b214d7e5..6a0f5f10874e38 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h @@ -31,8 +31,9 @@ class SMTConstraintManager : public clang::ento::SimpleConstraintManager { mutable llvm::SMTSolverRef Solver = llvm::CreateZ3Solver(); public: - SMTConstraintManager(clang::ento::SubEngine *SE, clang::ento::SValBuilder &SB) - : SimpleConstraintManager(SE, SB) {} + SMTConstraintManager(clang::ento::ExprEngine *EE, + clang::ento::SValBuilder &SB) + : SimpleConstraintManager(EE, SB) {} virtual ~SMTConstraintManager() = default; //===------------------------------------------------------------------===// diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h index 6bf5e94afdbb63..87e927f5b48005 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h @@ -21,12 +21,12 @@ namespace clang { namespace ento { class SimpleConstraintManager : public ConstraintManager { - SubEngine *SU; + ExprEngine *EE; SValBuilder &SVB; public: - SimpleConstraintManager(SubEngine *subengine, SValBuilder &SB) - : SU(subengine), SVB(SB) {} + SimpleConstraintManager(ExprEngine *exprengine, SValBuilder &SB) + : EE(exprengine), SVB(SB) {} ~SimpleConstraintManager() override; diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h deleted file mode 100644 index a7f3c28d4373a9..00000000000000 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h +++ /dev/null @@ -1,178 +0,0 @@ -//== SubEngine.h - Interface of the subengine of CoreEngine --------*- C++ -*-// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines the interface of a subengine of the CoreEngine. -// -//===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SUBENGINE_H -#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SUBENGINE_H - -#include "clang/Analysis/ProgramPoint.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" -#include "clang/StaticAnalyzer/Core/CheckerManager.h" - -namespace clang { - -class CFGBlock; -class CFGElement; -class LocationContext; -class Stmt; - -namespace cross_tu { -class CrossTranslationUnitContext; -} - -namespace ento { - -struct NodeBuilderContext; -class AnalysisManager; -class ExplodedNodeSet; -class ExplodedNode; -class ProgramState; -class ProgramStateManager; -class BlockCounter; -class BranchNodeBuilder; -class IndirectGotoNodeBuilder; -class SwitchNodeBuilder; -class EndOfFunctionNodeBuilder; -class NodeBuilderWithSinks; -class MemRegion; - -class SubEngine { - virtual void anchor(); -public: - virtual ~SubEngine() {} - - virtual ProgramStateRef getInitialState(const LocationContext *InitLoc) = 0; - - virtual AnalysisManager &getAnalysisManager() = 0; - - virtual cross_tu::CrossTranslationUnitContext * - getCrossTranslationUnitContext() = 0; - - virtual ProgramStateManager &getStateManager() = 0; - - /// Called by CoreEngine. Used to generate new successor - /// nodes by processing the 'effects' of a block-level statement. - virtual void processCFGElement(const CFGElement E, ExplodedNode* Pred, - unsigned StmtIdx, NodeBuilderContext *Ctx)=0; - - /// Called by CoreEngine when it starts processing a CFGBlock. The - /// SubEngine is expected to populate dstNodes with new nodes representing - /// updated analysis state, or generate no nodes at all if it doesn't. - virtual void processCFGBlockEntrance(const BlockEdge &L, - NodeBuilderWithSinks &nodeBuilder, - ExplodedNode *Pred) = 0; - - /// Called by CoreEngine. Used to generate successor - /// nodes by processing the 'effects' of a branch condition. - virtual void processBranch(const Stmt *Condition, - NodeBuilderContext& BuilderCtx, - ExplodedNode *Pred, - ExplodedNodeSet &Dst, - const CFGBlock *DstT, - const CFGBlock *DstF) = 0; - - /// Called by CoreEngine. - /// Used to generate successor nodes for temporary destructors depending - /// on whether the corresponding constructor was visited. - virtual void processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE, - NodeBuilderContext &BldCtx, - ExplodedNode *Pred, - ExplodedNodeSet &Dst, - const CFGBlock *DstT, - const CFGBlock *DstF) = 0; - - /// Called by CoreEngine. Used to processing branching behavior - /// at static initializers. - virtual void processStaticInitializer(const DeclStmt *DS, - NodeBuilderContext& BuilderCtx, - ExplodedNode *Pred, - ExplodedNodeSet &Dst, - const CFGBlock *DstT, - const CFGBlock *DstF) = 0; - - /// Called by CoreEngine. Used to generate successor - /// nodes by processing the 'effects' of a computed goto jump. - virtual void processIndirectGoto(IndirectGotoNodeBuilder& builder) = 0; - - /// Called by CoreEngine. Used to generate successor - /// nodes by processing the 'effects' of a switch statement. - virtual void processSwitch(SwitchNodeBuilder& builder) = 0; - - /// Called by CoreEngine. Used to notify checkers that processing a - /// function has begun. Called for both inlined and and top-level functions. - virtual void processBeginOfFunction(NodeBuilderContext &BC, - ExplodedNode *Pred, - ExplodedNodeSet &Dst, - const BlockEdge &L) = 0; - - /// Called by CoreEngine. Used to notify checkers that processing a - /// function has ended. Called for both inlined and and top-level functions. - virtual void processEndOfFunction(NodeBuilderContext& BC, - ExplodedNode *Pred, - const ReturnStmt *RS = nullptr) = 0; - - // Generate the entry node of the callee. - virtual void processCallEnter(NodeBuilderContext& BC, CallEnter CE, - ExplodedNode *Pred) = 0; - - // Generate the first post callsite node. - virtual void processCallExit(ExplodedNode *Pred) = 0; - - /// Called by ConstraintManager. Used to call checker-specific - /// logic for handling assumptions on symbolic values. - virtual ProgramStateRef processAssume(ProgramStateRef state, - SVal cond, bool assumption) = 0; - - /// processRegionChanges - Called by ProgramStateManager whenever a change is - /// made to the store. Used to update checkers that track region values. - virtual ProgramStateRef - processRegionChanges(ProgramStateRef state, - const InvalidatedSymbols *invalidated, - ArrayRef ExplicitRegions, - ArrayRef Regions, - const LocationContext *LCtx, - const CallEvent *Call) = 0; - - - inline ProgramStateRef - processRegionChange(ProgramStateRef state, - const MemRegion* MR, - const LocationContext *LCtx) { - return processRegionChanges(state, nullptr, MR, MR, LCtx, nullptr); - } - - virtual ProgramStateRef processPointerEscapedOnBind( - ProgramStateRef State, ArrayRef> LocAndVals, - const LocationContext *LCtx, PointerEscapeKind Kind, - const CallEvent *Call) = 0; - - virtual ProgramStateRef - notifyCheckersOfPointerEscape(ProgramStateRef State, - const InvalidatedSymbols *Invalidated, - ArrayRef ExplicitRegions, - const CallEvent *Call, - RegionAndSymbolInvalidationTraits &HTraits) = 0; - - /// printJson - Called by ProgramStateManager to print checker-specific data. - virtual void printJson(raw_ostream &Out, ProgramStateRef State, - const LocationContext *LCtx, const char *NL, - unsigned int Space, bool IsDot) const = 0; - - /// Called by CoreEngine when the analysis worklist is either empty or the - // maximum number of analysis steps have been reached. - virtual void processEndWorklist() = 0; -}; - -} // end GR namespace - -} // end clang namespace - -#endif diff --git a/clang/include/clang/Tooling/Syntax/Nodes.h b/clang/include/clang/Tooling/Syntax/Nodes.h index f4d482bb848c63..e240becbf883ab 100644 --- a/clang/include/clang/Tooling/Syntax/Nodes.h +++ b/clang/include/clang/Tooling/Syntax/Nodes.h @@ -40,6 +40,9 @@ enum class NodeKind : uint16_t { // Expressions. UnknownExpression, + PrefixUnaryOperatorExpression, + PostfixUnaryOperatorExpression, + BinaryOperatorExpression, // Statements. UnknownStatement, @@ -104,6 +107,11 @@ enum class NodeRole : uint8_t { BodyStatement, // Roles specific to particular node kinds. + UnaryOperatorExpression_operatorToken, + UnaryOperatorExpression_operand, + BinaryOperatorExpression_leftHandSide, + BinaryOperatorExpression_operatorToken, + BinaryOperatorExpression_rightHandSide, CaseStatement_value, IfStatement_thenStatement, IfStatement_elseKeyword, @@ -158,6 +166,68 @@ class UnknownExpression final : public Expression { } }; +/// An abstract class for prefix and postfix unary operators. +class UnaryOperatorExpression : public Expression { +public: + UnaryOperatorExpression(NodeKind K) : Expression(K) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::PrefixUnaryOperatorExpression || + N->kind() == NodeKind::PostfixUnaryOperatorExpression; + } + syntax::Leaf *operatorToken(); + syntax::Expression *operand(); +}; + +/// +/// +/// For example: +/// +a -b +/// !c not c +/// ~d compl d +/// *e &f +/// ++h --h +/// __real i __imag i +class PrefixUnaryOperatorExpression final : public UnaryOperatorExpression { +public: + PrefixUnaryOperatorExpression() + : UnaryOperatorExpression(NodeKind::PrefixUnaryOperatorExpression) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::PrefixUnaryOperatorExpression; + } +}; + +/// +/// +/// For example: +/// a++ +/// b-- +class PostfixUnaryOperatorExpression final : public UnaryOperatorExpression { +public: + PostfixUnaryOperatorExpression() + : UnaryOperatorExpression(NodeKind::PostfixUnaryOperatorExpression) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::PostfixUnaryOperatorExpression; + } +}; + +/// +/// +/// For example: +/// a + b +/// a bitor 1 +/// a |= b +/// a and_eq b +class BinaryOperatorExpression final : public Expression { +public: + BinaryOperatorExpression() : Expression(NodeKind::BinaryOperatorExpression) {} + static bool classof(const Node *N) { + return N->kind() == NodeKind::BinaryOperatorExpression; + } + syntax::Expression *lhs(); + syntax::Leaf *operatorToken(); + syntax::Expression *rhs(); +}; + /// An abstract node for C++ statements, e.g. 'while', 'if', etc. /// FIXME: add accessors for semicolon of statements that have it. class Statement : public Tree { diff --git a/clang/include/clang/Tooling/Transformer/RangeSelector.h b/clang/include/clang/Tooling/Transformer/RangeSelector.h index 9f556d206321c6..eaab3fc4c0c787 100644 --- a/clang/include/clang/Tooling/Transformer/RangeSelector.h +++ b/clang/include/clang/Tooling/Transformer/RangeSelector.h @@ -43,7 +43,7 @@ RangeSelector before(RangeSelector Selector); /// Selects the the point immediately following \p Selector. That is, the /// (empty) range [E,E), when \p Selector selects either /// * the CharRange [B,E) or -/// * the TokenRange [B,E'] where the token at E' spans the range [E,E'). +/// * the TokenRange [B,E'] where the token at E' spans the range [E',E). RangeSelector after(RangeSelector Selector); /// Selects a node, including trailing semicolon (for non-expression diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 27b3ae3ef00ec4..e6800073ee58d6 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3224,6 +3224,15 @@ unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const { !(BuiltinID == Builtin::BIprintf || BuiltinID == Builtin::BImalloc)) return 0; + // As AMDGCN implementation of OpenMP does not have a device-side standard + // library, none of the predefined library functions except printf and malloc + // should be treated as a builtin i.e. 0 should be returned for them. + if (Context.getTargetInfo().getTriple().isAMDGCN() && + Context.getLangOpts().OpenMPIsDevice && + Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID) && + !(BuiltinID == Builtin::BIprintf || BuiltinID == Builtin::BImalloc)) + return 0; + return BuiltinID; } diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index fc2a166e11b4c3..4df6512e6c76c1 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -289,12 +289,10 @@ void DeclPrinter::ProcessDeclGroup(SmallVectorImpl& Decls) { } void DeclPrinter::Print(AccessSpecifier AS) { - switch(AS) { - case AS_none: llvm_unreachable("No access specifier!"); - case AS_public: Out << "public"; break; - case AS_protected: Out << "protected"; break; - case AS_private: Out << "private"; break; - } + const auto AccessSpelling = getAccessSpelling(AS); + if (AccessSpelling.empty()) + llvm_unreachable("No access specifier!"); + Out << AccessSpelling; } void DeclPrinter::PrintConstructorInitializers(CXXConstructorDecl *CDecl, diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 468540ddf06f68..4c175fff642178 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -2909,13 +2909,16 @@ Expr *Expr::IgnoreUnlessSpelledInSource() { Expr *LastE = nullptr; while (E != LastE) { LastE = E; - E = IgnoreExprNodes(E, IgnoreImplicitSingleStep, IgnoreImpCastsSingleStep, + E = IgnoreExprNodes(E, IgnoreImplicitSingleStep, + IgnoreImpCastsExtraSingleStep, IgnoreParensOnlySingleStep); auto SR = E->getSourceRange(); if (auto *C = dyn_cast(E)) { - if (C->getNumArgs() == 1) { + auto NumArgs = C->getNumArgs(); + if (NumArgs == 1 || + (NumArgs > 1 && isa(C->getArg(1)))) { Expr *A = C->getArg(0); if (A->getSourceRange() == SR || !isa(C)) E = A; @@ -2923,7 +2926,18 @@ Expr *Expr::IgnoreUnlessSpelledInSource() { } if (auto *C = dyn_cast(E)) { - Expr *ExprNode = C->getImplicitObjectArgument()->IgnoreParenImpCasts(); + Expr *ExprNode = C->getImplicitObjectArgument(); + if (ExprNode->getSourceRange() == SR) { + E = ExprNode; + continue; + } + if (auto *PE = dyn_cast(ExprNode)) { + if (PE->getSourceRange() == C->getSourceRange()) { + E = PE; + continue; + } + } + ExprNode = ExprNode->IgnoreParenImpCasts(); if (ExprNode->getSourceRange() == SR) E = ExprNode; } diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index 91281fb44bfa9e..8edfed673ce219 100644 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -1,5 +1,6 @@ #include "clang/AST/JSONNodeDumper.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" #include "clang/Lex/Lexer.h" #include "llvm/ADT/StringSwitch.h" @@ -465,13 +466,10 @@ JSONNodeDumper::createCXXRecordDefinitionData(const CXXRecordDecl *RD) { #undef FIELD2 std::string JSONNodeDumper::createAccessSpecifier(AccessSpecifier AS) { - switch (AS) { - case AS_none: return "none"; - case AS_private: return "private"; - case AS_protected: return "protected"; - case AS_public: return "public"; - } - llvm_unreachable("Unknown access specifier"); + const auto AccessSpelling = getAccessSpelling(AS); + if (AccessSpelling.empty()) + return "none"; + return AccessSpelling.str(); } llvm::json::Object diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index 14c4c78e5f39f5..fa1c80fc6bbf9e 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -136,6 +136,7 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_unified_address: case OMPC_unified_shared_memory: @@ -227,6 +228,7 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C) case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_unified_address: case OMPC_unified_shared_memory: @@ -1198,6 +1200,53 @@ OMPUseDevicePtrClause::CreateEmpty(const ASTContext &C, return new (Mem) OMPUseDevicePtrClause(Sizes); } +OMPUseDeviceAddrClause * +OMPUseDeviceAddrClause::Create(const ASTContext &C, const OMPVarListLocTy &Locs, + ArrayRef Vars, + ArrayRef Declarations, + MappableExprComponentListsRef ComponentLists) { + OMPMappableExprListSizeTy Sizes; + Sizes.NumVars = Vars.size(); + Sizes.NumUniqueDeclarations = getUniqueDeclarationsTotalNumber(Declarations); + Sizes.NumComponentLists = ComponentLists.size(); + Sizes.NumComponents = getComponentsTotalNumber(ComponentLists); + + // We need to allocate: + // 3 x NumVars x Expr* - we have an original list expression for each clause + // list entry and an equal number of private copies and inits. + // NumUniqueDeclarations x ValueDecl* - unique base declarations associated + // with each component list. + // (NumUniqueDeclarations + NumComponentLists) x unsigned - we specify the + // number of lists for each unique declaration and the size of each component + // list. + // NumComponents x MappableComponent - the total of all the components in all + // the lists. + void *Mem = C.Allocate( + totalSizeToAlloc( + Sizes.NumVars, Sizes.NumUniqueDeclarations, + Sizes.NumUniqueDeclarations + Sizes.NumComponentLists, + Sizes.NumComponents)); + + auto *Clause = new (Mem) OMPUseDeviceAddrClause(Locs, Sizes); + + Clause->setVarRefs(Vars); + Clause->setClauseInfo(Declarations, ComponentLists); + return Clause; +} + +OMPUseDeviceAddrClause * +OMPUseDeviceAddrClause::CreateEmpty(const ASTContext &C, + const OMPMappableExprListSizeTy &Sizes) { + void *Mem = C.Allocate( + totalSizeToAlloc( + Sizes.NumVars, Sizes.NumUniqueDeclarations, + Sizes.NumUniqueDeclarations + Sizes.NumComponentLists, + Sizes.NumComponents)); + return new (Mem) OMPUseDeviceAddrClause(Sizes); +} + OMPIsDevicePtrClause * OMPIsDevicePtrClause::Create(const ASTContext &C, const OMPVarListLocTy &Locs, ArrayRef Vars, @@ -1934,6 +1983,15 @@ void OMPClausePrinter::VisitOMPUseDevicePtrClause(OMPUseDevicePtrClause *Node) { } } +void OMPClausePrinter::VisitOMPUseDeviceAddrClause( + OMPUseDeviceAddrClause *Node) { + if (!Node->varlist_empty()) { + OS << "use_device_addr"; + VisitOMPClauseList(Node, '('); + OS << ")"; + } +} + void OMPClausePrinter::VisitOMPIsDevicePtrClause(OMPIsDevicePtrClause *Node) { if (!Node->varlist_empty()) { OS << "is_device_ptr"; diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index bd2eeb699e65e0..e573c045cb7ab5 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -784,6 +784,10 @@ void OMPClauseProfiler::VisitOMPUseDevicePtrClause( const OMPUseDevicePtrClause *C) { VisitOMPClauseList(C); } +void OMPClauseProfiler::VisitOMPUseDeviceAddrClause( + const OMPUseDeviceAddrClause *C) { + VisitOMPClauseList(C); +} void OMPClauseProfiler::VisitOMPIsDevicePtrClause( const OMPIsDevicePtrClause *C) { VisitOMPClauseList(C); diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 9dbe5570753915..1b640a8cbe40e6 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -17,6 +17,7 @@ #include "clang/AST/LocInfoType.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" using namespace clang; @@ -436,19 +437,10 @@ void TextNodeDumper::dumpName(const NamedDecl *ND) { } void TextNodeDumper::dumpAccessSpecifier(AccessSpecifier AS) { - switch (AS) { - case AS_none: - break; - case AS_public: - OS << "public"; - break; - case AS_protected: - OS << "protected"; - break; - case AS_private: - OS << "private"; - break; - } + const auto AccessSpelling = getAccessSpelling(AS); + if (AccessSpelling.empty()) + return; + OS << AccessSpelling; } void TextNodeDumper::dumpCleanupObject( diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp index b09be431785167..5e305534c812ed 100644 --- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp +++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp @@ -280,13 +280,15 @@ const Stmt *ExprMutationAnalyzer::findDirectMutation(const Expr *Exp) { const auto AsNonConstRefReturn = returnStmt(hasReturnValue( maybeEvalCommaExpr(equalsNode(Exp)))); - const auto Matches = - match(findAll(stmt(anyOf(AsAssignmentLhs, AsIncDecOperand, AsNonConstThis, - AsAmpersandOperand, AsPointerFromArrayDecay, - AsOperatorArrowThis, AsNonConstRefArg, - AsLambdaRefCaptureInit, AsNonConstRefReturn)) - .bind("stmt")), - Stm, Context); + const auto Matches = match( + traverse( + ast_type_traits::TK_AsIs, + findAll(stmt(anyOf(AsAssignmentLhs, AsIncDecOperand, AsNonConstThis, + AsAmpersandOperand, AsPointerFromArrayDecay, + AsOperatorArrowThis, AsNonConstRefArg, + AsLambdaRefCaptureInit, AsNonConstRefReturn)) + .bind("stmt"))), + Stm, Context); return selectFirst("stmt", Matches); } @@ -385,12 +387,15 @@ const Stmt *ExprMutationAnalyzer::findFunctionArgMutation(const Expr *Exp) { const auto IsInstantiated = hasDeclaration(isInstantiated()); const auto FuncDecl = hasDeclaration(functionDecl().bind("func")); const auto Matches = match( - findAll(expr(anyOf(callExpr(NonConstRefParam, IsInstantiated, FuncDecl, + traverse( + ast_type_traits::TK_AsIs, + findAll( + expr(anyOf(callExpr(NonConstRefParam, IsInstantiated, FuncDecl, unless(callee(namedDecl(hasAnyName( "::std::move", "::std::forward"))))), cxxConstructExpr(NonConstRefParam, IsInstantiated, FuncDecl))) - .bind(NodeID::value)), + .bind(NodeID::value))), Stm, Context); for (const auto &Nodes : Matches) { const auto *Exp = Nodes.getNodeAs(NodeID::value); diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 8dddb66fa322a1..a000e4dee3b853 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -163,6 +163,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, case OMPC_hint: case OMPC_uniform: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_unified_address: case OMPC_unified_shared_memory: @@ -411,6 +412,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_hint: case OMPC_uniform: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_unified_address: case OMPC_unified_shared_memory: diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h index d0e88e223e9555..6c9060aa3f7bf4 100644 --- a/clang/lib/Basic/Targets/AMDGPU.h +++ b/clang/lib/Basic/Targets/AMDGPU.h @@ -131,6 +131,11 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo { }); StringRef S(Name); + if (S == "A") { + Info.setRequiresImmediate(); + return true; + } + bool HasLeftParen = false; if (S.front() == '{') { HasLeftParen = true; diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h index 6261a49c4fdea6..7c19a96a99c748 100644 --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -276,11 +276,12 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo { break; case 'Q': // Memory operand that is an offset from a register (it is // usually better to use `m' or `es' in asm statements) + Info.setAllowsRegister(); + LLVM_FALLTHROUGH; case 'Z': // Memory operand that is an indexed or indirect from a // register (it is usually better to use `m' or `es' in // asm statements) Info.setAllowsMemory(); - Info.setAllowsRegister(); break; case 'R': // AIX TOC entry case 'a': // Address operand that is an indexed or indirect from a diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 1adae1a7ea42ab..b5129249c016d1 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -1271,6 +1271,8 @@ llvm::Function *CodeGenFunction::generateBuiltinOSLogHelperFunction( FunctionDecl *FD = FunctionDecl::Create( Ctx, Ctx.getTranslationUnitDecl(), SourceLocation(), SourceLocation(), II, FuncionTy, nullptr, SC_PrivateExtern, false, false); + // Avoid generating debug location info for the function. + FD->setImplicit(); StartFunction(FD, ReturnTy, Fn, FI, Args); diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 6831f8248225f7..c324b9fa501e59 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -4822,6 +4822,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex, llvm::Attribute::StrictFP); + // Add call-site nomerge attribute if exists. + if (InNoMergeAttributedStmt) + Attrs = + Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex, + llvm::Attribute::NoMerge); + // Apply some call-site-specific attributes. // TODO: work this into building the attribute set. diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index d821eb2d5595f3..de3d1b12914649 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -472,7 +472,7 @@ void CodeGenFunction::EmitStartEHSpec(const Decl *D) { // In wasm we currently treat 'throw()' in the same way as 'noexcept'. In // case of throw with types, we ignore it and print a warning for now. // TODO Correctly handle exception specification in wasm - if (getTarget().getCXXABI() == TargetCXXABI::WebAssembly) { + if (CGM.getLangOpts().WasmExceptions) { if (EST == EST_DynamicNone) EHStack.pushTerminate(); else @@ -560,7 +560,7 @@ void CodeGenFunction::EmitEndEHSpec(const Decl *D) { // In wasm we currently treat 'throw()' in the same way as 'noexcept'. In // case of throw with types, we ignore it and print a warning for now. // TODO Correctly handle exception specification in wasm - if (getTarget().getCXXABI() == TargetCXXABI::WebAssembly) { + if (CGM.getLangOpts().WasmExceptions) { if (EST == EST_DynamicNone) EHStack.popTerminate(); return; diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index ceecbd4dc137ac..3559e77fc76409 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -25,6 +25,7 @@ #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/MDBuilder.h" +#include "llvm/Support/SaveAndRestore.h" using namespace clang; using namespace CodeGen; @@ -608,6 +609,13 @@ void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) { } void CodeGenFunction::EmitAttributedStmt(const AttributedStmt &S) { + bool nomerge = false; + for (const auto *A : S.getAttrs()) + if (A->getKind() == attr::NoMerge) { + nomerge = true; + break; + } + SaveAndRestore save_nomerge(InNoMergeAttributedStmt, nomerge); EmitStmt(S.getSubStmt(), S.getAttrs()); } diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index b6d45f026bbfd8..ae4e3400fcbc4d 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -1730,8 +1730,19 @@ void CodeGenFunction::EmitOMPInnerLoop( auto CondBlock = createBasicBlock("omp.inner.for.cond"); EmitBlock(CondBlock); const SourceRange R = S.getSourceRange(); - LoopStack.push(CondBlock, SourceLocToDebugLoc(R.getBegin()), - SourceLocToDebugLoc(R.getEnd())); + + // If attributes are attached, push to the basic block with them. + const auto &OMPED = cast(S); + const CapturedStmt *ICS = OMPED.getInnermostCapturedStmt(); + const Stmt *SS = ICS->getCapturedStmt(); + const AttributedStmt *AS = dyn_cast_or_null(SS); + if (AS) + LoopStack.push(CondBlock, CGM.getContext(), CGM.getCodeGenOpts(), + AS->getAttrs(), SourceLocToDebugLoc(R.getBegin()), + SourceLocToDebugLoc(R.getEnd())); + else + LoopStack.push(CondBlock, SourceLocToDebugLoc(R.getBegin()), + SourceLocToDebugLoc(R.getEnd())); // If there are any cleanups between here and the loop-exit scope, // create a block to stage a loop exit along. @@ -4719,6 +4730,7 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind, case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_unified_address: case OMPC_unified_shared_memory: diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 731317aac0dc95..2b5871dbb11685 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -595,6 +595,9 @@ class CodeGenFunction : public CodeGenTypeCache { /// region. bool IsInPreservedAIRegion = false; + /// True if the current statement has nomerge attribute. + bool InNoMergeAttributedStmt = false; + const CodeGen::CGBlockInfo *BlockInfo = nullptr; llvm::Value *BlockPointer = nullptr; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 8ba7fb756ada84..89a95db086804b 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -493,6 +493,9 @@ void CodeGenModule::Release() { if (Context.getLangOpts().SemanticInterposition) // Require various optimization to respect semantic interposition. getModule().setSemanticInterposition(1); + else if (Context.getLangOpts().ExplicitNoSemanticInterposition) + // Allow dso_local on applicable targets. + getModule().setSemanticInterposition(0); if (CodeGenOpts.EmitCodeView) { // Indicate that we want CodeView in the metadata. @@ -4133,17 +4136,24 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, GV->setAlignment(getContext().getDeclAlign(D).getAsAlign()); - // On Darwin, if the normal linkage of a C++ thread_local variable is - // LinkOnce or Weak, we keep the normal linkage to prevent multiple - // copies within a linkage unit; otherwise, the backing variable has - // internal linkage and all accesses should just be calls to the - // Itanium-specified entry point, which has the normal linkage of the - // variable. This is to preserve the ability to change the implementation - // behind the scenes. - if (!D->isStaticLocal() && D->getTLSKind() == VarDecl::TLS_Dynamic && + // On Darwin, unlike other Itanium C++ ABI platforms, the thread-wrapper + // function is only defined alongside the variable, not also alongside + // callers. Normally, all accesses to a thread_local go through the + // thread-wrapper in order to ensure initialization has occurred, underlying + // variable will never be used other than the thread-wrapper, so it can be + // converted to internal linkage. + // + // However, if the variable has the 'constinit' attribute, it _can_ be + // referenced directly, without calling the thread-wrapper, so the linkage + // must not be changed. + // + // Additionally, if the variable isn't plain external linkage, e.g. if it's + // weak or linkonce, the de-duplication semantics are important to preserve, + // so we don't change the linkage. + if (D->getTLSKind() == VarDecl::TLS_Dynamic && + Linkage == llvm::GlobalValue::ExternalLinkage && Context.getTargetInfo().getTriple().isOSDarwin() && - !llvm::GlobalVariable::isLinkOnceLinkage(Linkage) && - !llvm::GlobalVariable::isWeakLinkage(Linkage)) + !D->hasAttr()) Linkage = llvm::GlobalValue::InternalLinkage; GV->setLinkage(Linkage); diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp index 3c91a04d54642f..e810f608ab787f 100644 --- a/clang/lib/CodeGen/CodeGenPGO.cpp +++ b/clang/lib/CodeGen/CodeGenPGO.cpp @@ -52,9 +52,10 @@ void CodeGenPGO::setFuncName(llvm::Function *Fn) { enum PGOHashVersion : unsigned { PGO_HASH_V1, PGO_HASH_V2, + PGO_HASH_V3, // Keep this set to the latest hash version. - PGO_HASH_LATEST = PGO_HASH_V2 + PGO_HASH_LATEST = PGO_HASH_V3 }; namespace { @@ -122,7 +123,7 @@ class PGOHash { BinaryOperatorGE, BinaryOperatorEQ, BinaryOperatorNE, - // The preceding values are available with PGO_HASH_V2. + // The preceding values are available since PGO_HASH_V2. // Keep this last. It's for the static assert that follows. LastHashType @@ -144,7 +145,9 @@ static PGOHashVersion getPGOHashVersion(llvm::IndexedInstrProfReader *PGOReader, CodeGenModule &CGM) { if (PGOReader->getVersion() <= 4) return PGO_HASH_V1; - return PGO_HASH_V2; + if (PGOReader->getVersion() <= 5) + return PGO_HASH_V2; + return PGO_HASH_V3; } /// A RecursiveASTVisitor that fills a map of statements to PGO counters. @@ -288,7 +291,7 @@ struct MapRegionCounters : public RecursiveASTVisitor { return PGOHash::BinaryOperatorLAnd; if (BO->getOpcode() == BO_LOr) return PGOHash::BinaryOperatorLOr; - if (HashVersion == PGO_HASH_V2) { + if (HashVersion >= PGO_HASH_V2) { switch (BO->getOpcode()) { default: break; @@ -310,7 +313,7 @@ struct MapRegionCounters : public RecursiveASTVisitor { } } - if (HashVersion == PGO_HASH_V2) { + if (HashVersion >= PGO_HASH_V2) { switch (S->getStmtClass()) { default: break; @@ -747,13 +750,21 @@ uint64_t PGOHash::finalize() { return Working; // Check for remaining work in Working. - if (Working) - MD5.update(Working); + if (Working) { + // Keep the buggy behavior from v1 and v2 for backward-compatibility. This + // is buggy because it converts a uint64_t into an array of uint8_t. + if (HashVersion < PGO_HASH_V3) { + MD5.update({(uint8_t)Working}); + } else { + using namespace llvm::support; + uint64_t Swapped = endian::byte_swap(Working); + MD5.update(llvm::makeArrayRef((uint8_t *)&Swapped, sizeof(Swapped))); + } + } // Finalize the MD5 and return the hash. llvm::MD5::MD5Result Result; MD5.final(Result); - using namespace llvm::support; return Result.low(); } diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index bc186fa5a5982c..6281991ebf04e8 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -14,10 +14,10 @@ #include "clang/Driver/ToolChain.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/SpecialCaseList.h" #include "llvm/Support/TargetParser.h" +#include "llvm/Support/VirtualFileSystem.h" #include using namespace clang; @@ -43,11 +43,12 @@ static const SanitizerMask SupportsCoverage = SanitizerKind::KernelAddress | SanitizerKind::KernelHWAddress | SanitizerKind::MemTag | SanitizerKind::Memory | SanitizerKind::KernelMemory | SanitizerKind::Leak | - SanitizerKind::Undefined | SanitizerKind::Integer | + SanitizerKind::Undefined | SanitizerKind::Integer | SanitizerKind::Bounds | SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | SanitizerKind::DataFlow | SanitizerKind::Fuzzer | SanitizerKind::FuzzerNoLink | SanitizerKind::FloatDivideByZero | - SanitizerKind::SafeStack | SanitizerKind::ShadowCallStack; + SanitizerKind::SafeStack | SanitizerKind::ShadowCallStack | + SanitizerKind::Thread; static const SanitizerMask RecoverableByDefault = SanitizerKind::Undefined | SanitizerKind::Integer | SanitizerKind::ImplicitConversion | SanitizerKind::Nullability | @@ -488,8 +489,7 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, << lastArgumentForMask(D, Args, Kinds & NeedsLTO) << "-flto"; } - if ((Kinds & SanitizerKind::ShadowCallStack) && - TC.getTriple().getArch() == llvm::Triple::aarch64 && + if ((Kinds & SanitizerKind::ShadowCallStack) && TC.getTriple().isAArch64() && !llvm::AArch64::isX18ReservedByDefault(TC.getTriple()) && !Args.hasArg(options::OPT_ffixed_x18)) { D.Diag(diag::err_drv_argument_only_allowed_with) diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 6258276a00928f..ad66e8e6b5d311 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -975,15 +975,12 @@ SanitizerMask ToolChain::getSupportedSanitizers() const { if (getTriple().getArch() == llvm::Triple::x86 || getTriple().getArch() == llvm::Triple::x86_64 || getTriple().getArch() == llvm::Triple::arm || - getTriple().getArch() == llvm::Triple::aarch64 || getTriple().getArch() == llvm::Triple::wasm32 || - getTriple().getArch() == llvm::Triple::wasm64) + getTriple().getArch() == llvm::Triple::wasm64 || getTriple().isAArch64()) Res |= SanitizerKind::CFIICall; - if (getTriple().getArch() == llvm::Triple::x86_64 || - getTriple().getArch() == llvm::Triple::aarch64) + if (getTriple().getArch() == llvm::Triple::x86_64 || getTriple().isAArch64()) Res |= SanitizerKind::ShadowCallStack; - if (getTriple().getArch() == llvm::Triple::aarch64 || - getTriple().getArch() == llvm::Triple::aarch64_be) + if (getTriple().isAArch64()) Res |= SanitizerKind::MemTag; return Res; } diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp index 6fbff61f765652..df2e30da32a8c6 100644 --- a/clang/lib/Driver/ToolChains/AIX.cpp +++ b/clang/lib/Driver/ToolChains/AIX.cpp @@ -81,6 +81,7 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { const AIX &ToolChain = static_cast(getToolChain()); + const Driver &D = ToolChain.getDriver(); ArgStringList CmdArgs; const bool IsArch32Bit = ToolChain.getTriple().isArch32Bit(); @@ -129,6 +130,12 @@ void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.MakeArgString(ToolChain.GetFilePath(getCrt0Basename()))); } + // Collect all static constructor and destructor functions in CXX mode. This + // has to come before AddLinkerInputs as the implied option needs to precede + // any other '-bcdtors' settings or '-bnocdtors' that '-Wl' might forward. + if (D.CCCIsCXX()) + CmdArgs.push_back("-bcdtors:all:0:s"); + // Specify linker input file(s). AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp index 193ccad98f5299..3e51bd00bae478 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -107,11 +107,18 @@ RocmInstallationDetector::RocmInstallationDetector( // the Windows-esque layout the ROCm packages use with the host architecture // subdirectory of bin. + // Strip off directory (usually bin) StringRef ParentDir = llvm::sys::path::parent_path(InstallDir); - if (ParentDir == HostTriple.getArchName()) + StringRef ParentName = llvm::sys::path::filename(ParentDir); + + // Some builds use bin/{host arch}, so go up again. + if (ParentName == "bin") { ParentDir = llvm::sys::path::parent_path(ParentDir); + ParentName = llvm::sys::path::filename(ParentDir); + } - if (ParentDir == "bin") { + if (ParentName == "llvm") { + // Some versions of the rocm llvm package install to /opt/rocm/llvm/bin Candidates.emplace_back(llvm::sys::path::parent_path(ParentDir).str(), /*StrictChecking=*/true); } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index deb60ed68cfca1..f33983db3e1eb0 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4471,10 +4471,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } - if (Args.hasFlag(options::OPT_fsemantic_interposition, - options::OPT_fno_semantic_interposition, false) && - RelocationModel != llvm::Reloc::Static && !IsPIE) - CmdArgs.push_back("-fsemantic-interposition"); + // The default is -fno-semantic-interposition. We render it just because we + // require explicit -fno-semantic-interposition to infer dso_local. + if (Arg *A = Args.getLastArg(options::OPT_fsemantic_interposition, + options::OPT_fno_semantic_interposition)) + if (RelocationModel != llvm::Reloc::Static && !IsPIE) + A->render(Args, CmdArgs); CmdArgs.push_back("-mthread-model"); if (Arg *A = Args.getLastArg(options::OPT_mthread_model)) { diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index d6451447a9241c..85a1a4e1ac07d5 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -774,7 +774,7 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back("--export-dynamic"); if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic) - CmdArgs.push_back("-export-dynamic-symbol=__cfi_check"); + CmdArgs.push_back("--export-dynamic-symbol=__cfi_check"); return !StaticRuntimes.empty() || !NonWholeStaticRuntimes.empty(); } diff --git a/clang/lib/Driver/ToolChains/PS4CPU.h b/clang/lib/Driver/ToolChains/PS4CPU.h index 27969bcf3726fb..6b1efd25f43a82 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.h +++ b/clang/lib/Driver/ToolChains/PS4CPU.h @@ -100,6 +100,8 @@ class LLVM_LIBRARY_VISIBILITY PS4CPU : public Generic_ELF { return llvm::DenormalMode::getPreserveSign(); } + bool useRelaxRelocations() const override { return true; } + protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; diff --git a/clang/lib/Driver/XRayArgs.cpp b/clang/lib/Driver/XRayArgs.cpp index 54c15685d3898f..f233267b498469 100644 --- a/clang/lib/Driver/XRayArgs.cpp +++ b/clang/lib/Driver/XRayArgs.cpp @@ -13,10 +13,10 @@ #include "clang/Driver/ToolChain.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/SpecialCaseList.h" +#include "llvm/Support/VirtualFileSystem.h" using namespace clang; using namespace clang::driver; diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 03b6e0c9ef7440..b8da2c23b55ac0 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -1962,7 +1962,7 @@ void UnwrappedLineParser::parseIfThenElse() { if (FormatTok->Tok.is(tok::l_paren)) parseParens(); // handle [[likely]] / [[unlikely]] - if (FormatTok->is(tok::l_square)) + if (FormatTok->is(tok::l_square) && tryToParseSimpleAttribute()) parseSquare(); bool NeedsUnwrappedLine = false; if (FormatTok->Tok.is(tok::l_brace)) { @@ -1981,7 +1981,7 @@ void UnwrappedLineParser::parseIfThenElse() { if (FormatTok->Tok.is(tok::kw_else)) { nextToken(); // handle [[likely]] / [[unlikely]] - if (FormatTok->is(tok::l_square)) + if (FormatTok->Tok.is(tok::l_square) && tryToParseSimpleAttribute()) parseSquare(); if (FormatTok->Tok.is(tok::l_brace)) { CompoundStatementIndenter Indenter(this, Style, Line->Level); @@ -2343,6 +2343,51 @@ bool UnwrappedLineParser::parseEnum() { // "} n, m;" will end up in one unwrapped line. } +namespace { +// A class used to set and restore the Token position when peeking +// ahead in the token source. +class ScopedTokenPosition { + unsigned StoredPosition; + FormatTokenSource *Tokens; + +public: + ScopedTokenPosition(FormatTokenSource *Tokens) : Tokens(Tokens) { + assert(Tokens && "Tokens expected to not be null"); + StoredPosition = Tokens->getPosition(); + } + + ~ScopedTokenPosition() { Tokens->setPosition(StoredPosition); } +}; +} // namespace + +// Look to see if we have [[ by looking ahead, if +// its not then rewind to the original position. +bool UnwrappedLineParser::tryToParseSimpleAttribute() { + ScopedTokenPosition AutoPosition(Tokens); + FormatToken *Tok = Tokens->getNextToken(); + // We already read the first [ check for the second. + if (Tok && !Tok->is(tok::l_square)) { + return false; + } + // Double check that the attribute is just something + // fairly simple. + while (Tok) { + if (Tok->is(tok::r_square)) { + break; + } + Tok = Tokens->getNextToken(); + } + Tok = Tokens->getNextToken(); + if (Tok && !Tok->is(tok::r_square)) { + return false; + } + Tok = Tokens->getNextToken(); + if (Tok && Tok->is(tok::semi)) { + return false; + } + return true; +} + void UnwrappedLineParser::parseJavaEnumBody() { // Determine whether the enum is simple, i.e. does not have a semicolon or // constants with class bodies. Simple enums can be formatted like braced diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h index 8d4118ab6dc7de..8b3aa4c84edbad 100644 --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -134,6 +134,7 @@ class UnwrappedLineParser { bool tryToParseLambdaIntroducer(); bool tryToParsePropertyAccessor(); void tryToParseJSFunction(); + bool tryToParseSimpleAttribute(); void addUnwrappedLine(); bool eof() const; // LevelDifference is the difference of levels after and before the current diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index b4bc027e832b1a..1d820090f8109e 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3049,6 +3049,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, } Opts.SemanticInterposition = Args.hasArg(OPT_fsemantic_interposition); + // An explicit -fno-semantic-interposition infers dso_local. + Opts.ExplicitNoSemanticInterposition = + Args.hasArg(OPT_fno_semantic_interposition); // -mrtd option if (Arg *A = Args.getLastArg(OPT_mrtd)) { @@ -3106,7 +3109,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // Set the flag to prevent the implementation from emitting device exception // handling code for those requiring so. - if ((Opts.OpenMPIsDevice && T.isNVPTX()) || Opts.OpenCLCPlusPlus) { + if ((Opts.OpenMPIsDevice && (T.isNVPTX() || T.isAMDGCN())) || + Opts.OpenCLCPlusPlus) { Opts.Exceptions = 0; Opts.CXXExceptions = 0; } @@ -3140,6 +3144,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, TT.getArch() == llvm::Triple::ppc64le || TT.getArch() == llvm::Triple::nvptx || TT.getArch() == llvm::Triple::nvptx64 || + TT.getArch() == llvm::Triple::amdgcn || TT.getArch() == llvm::Triple::x86 || TT.getArch() == llvm::Triple::x86_64)) Diags.Report(diag::err_drv_invalid_omp_target) << A->getValue(i); @@ -3157,13 +3162,13 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, << Opts.OMPHostIRFile; } - // Set CUDA mode for OpenMP target NVPTX if specified in options - Opts.OpenMPCUDAMode = Opts.OpenMPIsDevice && T.isNVPTX() && + // Set CUDA mode for OpenMP target NVPTX/AMDGCN if specified in options + Opts.OpenMPCUDAMode = Opts.OpenMPIsDevice && (T.isNVPTX() || T.isAMDGCN()) && Args.hasArg(options::OPT_fopenmp_cuda_mode); - // Set CUDA mode for OpenMP target NVPTX if specified in options + // Set CUDA mode for OpenMP target NVPTX/AMDGCN if specified in options Opts.OpenMPCUDAForceFullRuntime = - Opts.OpenMPIsDevice && T.isNVPTX() && + Opts.OpenMPIsDevice && (T.isNVPTX() || T.isAMDGCN()) && Args.hasArg(options::OPT_fopenmp_cuda_force_full_runtime); // Record whether the __DEPRECATED define was requested. diff --git a/clang/lib/Headers/avx512bwintrin.h b/clang/lib/Headers/avx512bwintrin.h index 37655840768351..4281a33d375c22 100644 --- a/clang/lib/Headers/avx512bwintrin.h +++ b/clang/lib/Headers/avx512bwintrin.h @@ -1504,13 +1504,14 @@ _mm512_maskz_sll_epi16(__mmask32 __U, __m512i __A, __m128i __B) } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_slli_epi16(__m512i __A, int __B) +_mm512_slli_epi16(__m512i __A, unsigned int __B) { return (__m512i)__builtin_ia32_psllwi512((__v32hi)__A, __B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_mask_slli_epi16(__m512i __W, __mmask32 __U, __m512i __A, int __B) +_mm512_mask_slli_epi16(__m512i __W, __mmask32 __U, __m512i __A, + unsigned int __B) { return (__m512i)__builtin_ia32_selectw_512((__mmask32)__U, (__v32hi)_mm512_slli_epi16(__A, __B), @@ -1518,7 +1519,7 @@ _mm512_mask_slli_epi16(__m512i __W, __mmask32 __U, __m512i __A, int __B) } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_maskz_slli_epi16(__mmask32 __U, __m512i __A, int __B) +_mm512_maskz_slli_epi16(__mmask32 __U, __m512i __A, unsigned int __B) { return (__m512i)__builtin_ia32_selectw_512((__mmask32)__U, (__v32hi)_mm512_slli_epi16(__A, __B), @@ -1595,13 +1596,14 @@ _mm512_maskz_sra_epi16(__mmask32 __U, __m512i __A, __m128i __B) } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_srai_epi16(__m512i __A, int __B) +_mm512_srai_epi16(__m512i __A, unsigned int __B) { return (__m512i)__builtin_ia32_psrawi512((__v32hi)__A, __B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_mask_srai_epi16(__m512i __W, __mmask32 __U, __m512i __A, int __B) +_mm512_mask_srai_epi16(__m512i __W, __mmask32 __U, __m512i __A, + unsigned int __B) { return (__m512i)__builtin_ia32_selectw_512((__mmask32)__U, (__v32hi)_mm512_srai_epi16(__A, __B), @@ -1609,7 +1611,7 @@ _mm512_mask_srai_epi16(__m512i __W, __mmask32 __U, __m512i __A, int __B) } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_maskz_srai_epi16(__mmask32 __U, __m512i __A, int __B) +_mm512_maskz_srai_epi16(__mmask32 __U, __m512i __A, unsigned int __B) { return (__m512i)__builtin_ia32_selectw_512((__mmask32)__U, (__v32hi)_mm512_srai_epi16(__A, __B), @@ -1639,13 +1641,14 @@ _mm512_maskz_srl_epi16(__mmask32 __U, __m512i __A, __m128i __B) } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_srli_epi16(__m512i __A, int __B) +_mm512_srli_epi16(__m512i __A, unsigned int __B) { return (__m512i)__builtin_ia32_psrlwi512((__v32hi)__A, __B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_mask_srli_epi16(__m512i __W, __mmask32 __U, __m512i __A, int __B) +_mm512_mask_srli_epi16(__m512i __W, __mmask32 __U, __m512i __A, + unsigned int __B) { return (__m512i)__builtin_ia32_selectw_512((__mmask32)__U, (__v32hi)_mm512_srli_epi16(__A, __B), diff --git a/clang/lib/Headers/avx512fintrin.h b/clang/lib/Headers/avx512fintrin.h index 7465da379bdde5..fa22ef3fdd1884 100644 --- a/clang/lib/Headers/avx512fintrin.h +++ b/clang/lib/Headers/avx512fintrin.h @@ -5111,13 +5111,14 @@ _mm512_maskz_rolv_epi64 (__mmask8 __U, __m512i __A, __m512i __B) (__v8di)_mm512_setzero_si512()) static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_slli_epi32(__m512i __A, int __B) +_mm512_slli_epi32(__m512i __A, unsigned int __B) { return (__m512i)__builtin_ia32_pslldi512((__v16si)__A, __B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_mask_slli_epi32(__m512i __W, __mmask16 __U, __m512i __A, int __B) +_mm512_mask_slli_epi32(__m512i __W, __mmask16 __U, __m512i __A, + unsigned int __B) { return (__m512i)__builtin_ia32_selectd_512((__mmask16)__U, (__v16si)_mm512_slli_epi32(__A, __B), @@ -5125,20 +5126,20 @@ _mm512_mask_slli_epi32(__m512i __W, __mmask16 __U, __m512i __A, int __B) } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_maskz_slli_epi32(__mmask16 __U, __m512i __A, int __B) { +_mm512_maskz_slli_epi32(__mmask16 __U, __m512i __A, unsigned int __B) { return (__m512i)__builtin_ia32_selectd_512((__mmask16)__U, (__v16si)_mm512_slli_epi32(__A, __B), (__v16si)_mm512_setzero_si512()); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_slli_epi64(__m512i __A, int __B) +_mm512_slli_epi64(__m512i __A, unsigned int __B) { return (__m512i)__builtin_ia32_psllqi512((__v8di)__A, __B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_mask_slli_epi64(__m512i __W, __mmask8 __U, __m512i __A, int __B) +_mm512_mask_slli_epi64(__m512i __W, __mmask8 __U, __m512i __A, unsigned int __B) { return (__m512i)__builtin_ia32_selectq_512((__mmask8)__U, (__v8di)_mm512_slli_epi64(__A, __B), @@ -5146,7 +5147,7 @@ _mm512_mask_slli_epi64(__m512i __W, __mmask8 __U, __m512i __A, int __B) } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_maskz_slli_epi64(__mmask8 __U, __m512i __A, int __B) +_mm512_maskz_slli_epi64(__mmask8 __U, __m512i __A, unsigned int __B) { return (__m512i)__builtin_ia32_selectq_512((__mmask8)__U, (__v8di)_mm512_slli_epi64(__A, __B), @@ -5154,13 +5155,14 @@ _mm512_maskz_slli_epi64(__mmask8 __U, __m512i __A, int __B) } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_srli_epi32(__m512i __A, int __B) +_mm512_srli_epi32(__m512i __A, unsigned int __B) { return (__m512i)__builtin_ia32_psrldi512((__v16si)__A, __B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_mask_srli_epi32(__m512i __W, __mmask16 __U, __m512i __A, int __B) +_mm512_mask_srli_epi32(__m512i __W, __mmask16 __U, __m512i __A, + unsigned int __B) { return (__m512i)__builtin_ia32_selectd_512((__mmask16)__U, (__v16si)_mm512_srli_epi32(__A, __B), @@ -5168,20 +5170,21 @@ _mm512_mask_srli_epi32(__m512i __W, __mmask16 __U, __m512i __A, int __B) } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_maskz_srli_epi32(__mmask16 __U, __m512i __A, int __B) { +_mm512_maskz_srli_epi32(__mmask16 __U, __m512i __A, unsigned int __B) { return (__m512i)__builtin_ia32_selectd_512((__mmask16)__U, (__v16si)_mm512_srli_epi32(__A, __B), (__v16si)_mm512_setzero_si512()); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_srli_epi64(__m512i __A, int __B) +_mm512_srli_epi64(__m512i __A, unsigned int __B) { return (__m512i)__builtin_ia32_psrlqi512((__v8di)__A, __B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_mask_srli_epi64(__m512i __W, __mmask8 __U, __m512i __A, int __B) +_mm512_mask_srli_epi64(__m512i __W, __mmask8 __U, __m512i __A, + unsigned int __B) { return (__m512i)__builtin_ia32_selectq_512((__mmask8)__U, (__v8di)_mm512_srli_epi64(__A, __B), @@ -5189,7 +5192,8 @@ _mm512_mask_srli_epi64(__m512i __W, __mmask8 __U, __m512i __A, int __B) } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_maskz_srli_epi64(__mmask8 __U, __m512i __A, int __B) +_mm512_maskz_srli_epi64(__mmask8 __U, __m512i __A, + unsigned int __B) { return (__m512i)__builtin_ia32_selectq_512((__mmask8)__U, (__v8di)_mm512_srli_epi64(__A, __B), @@ -6593,13 +6597,14 @@ _mm_maskz_scalef_ss (__mmask8 __U, __m128 __A, __m128 __B) (int)(R)) static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_srai_epi32(__m512i __A, int __B) +_mm512_srai_epi32(__m512i __A, unsigned int __B) { return (__m512i)__builtin_ia32_psradi512((__v16si)__A, __B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_mask_srai_epi32(__m512i __W, __mmask16 __U, __m512i __A, int __B) +_mm512_mask_srai_epi32(__m512i __W, __mmask16 __U, __m512i __A, + unsigned int __B) { return (__m512i)__builtin_ia32_selectd_512((__mmask16)__U, (__v16si)_mm512_srai_epi32(__A, __B), @@ -6607,20 +6612,21 @@ _mm512_mask_srai_epi32(__m512i __W, __mmask16 __U, __m512i __A, int __B) } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_maskz_srai_epi32(__mmask16 __U, __m512i __A, int __B) { +_mm512_maskz_srai_epi32(__mmask16 __U, __m512i __A, + unsigned int __B) { return (__m512i)__builtin_ia32_selectd_512((__mmask16)__U, (__v16si)_mm512_srai_epi32(__A, __B), (__v16si)_mm512_setzero_si512()); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_srai_epi64(__m512i __A, int __B) +_mm512_srai_epi64(__m512i __A, unsigned int __B) { return (__m512i)__builtin_ia32_psraqi512((__v8di)__A, __B); } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_mask_srai_epi64(__m512i __W, __mmask8 __U, __m512i __A, int __B) +_mm512_mask_srai_epi64(__m512i __W, __mmask8 __U, __m512i __A, unsigned int __B) { return (__m512i)__builtin_ia32_selectq_512((__mmask8)__U, (__v8di)_mm512_srai_epi64(__A, __B), @@ -6628,7 +6634,7 @@ _mm512_mask_srai_epi64(__m512i __W, __mmask8 __U, __m512i __A, int __B) } static __inline__ __m512i __DEFAULT_FN_ATTRS512 -_mm512_maskz_srai_epi64(__mmask8 __U, __m512i __A, int __B) +_mm512_maskz_srai_epi64(__mmask8 __U, __m512i __A, unsigned int __B) { return (__m512i)__builtin_ia32_selectq_512((__mmask8)__U, (__v8di)_mm512_srai_epi64(__A, __B), diff --git a/clang/lib/Headers/avx512vlbwintrin.h b/clang/lib/Headers/avx512vlbwintrin.h index cd9f2400daa07d..6ed10ed9803bab 100644 --- a/clang/lib/Headers/avx512vlbwintrin.h +++ b/clang/lib/Headers/avx512vlbwintrin.h @@ -1939,7 +1939,7 @@ _mm256_maskz_sll_epi16(__mmask16 __U, __m256i __A, __m128i __B) } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_mask_slli_epi16(__m128i __W, __mmask8 __U, __m128i __A, int __B) +_mm_mask_slli_epi16(__m128i __W, __mmask8 __U, __m128i __A, unsigned int __B) { return (__m128i)__builtin_ia32_selectw_128((__mmask8)__U, (__v8hi)_mm_slli_epi16(__A, __B), @@ -1947,7 +1947,7 @@ _mm_mask_slli_epi16(__m128i __W, __mmask8 __U, __m128i __A, int __B) } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_maskz_slli_epi16 (__mmask8 __U, __m128i __A, int __B) +_mm_maskz_slli_epi16 (__mmask8 __U, __m128i __A, unsigned int __B) { return (__m128i)__builtin_ia32_selectw_128((__mmask8)__U, (__v8hi)_mm_slli_epi16(__A, __B), @@ -1955,7 +1955,8 @@ _mm_maskz_slli_epi16 (__mmask8 __U, __m128i __A, int __B) } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_mask_slli_epi16(__m256i __W, __mmask16 __U, __m256i __A, int __B) +_mm256_mask_slli_epi16(__m256i __W, __mmask16 __U, __m256i __A, + unsigned int __B) { return (__m256i)__builtin_ia32_selectw_256((__mmask16)__U, (__v16hi)_mm256_slli_epi16(__A, __B), @@ -1963,7 +1964,7 @@ _mm256_mask_slli_epi16(__m256i __W, __mmask16 __U, __m256i __A, int __B) } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_maskz_slli_epi16(__mmask16 __U, __m256i __A, int __B) +_mm256_maskz_slli_epi16(__mmask16 __U, __m256i __A, unsigned int __B) { return (__m256i)__builtin_ia32_selectw_256((__mmask16)__U, (__v16hi)_mm256_slli_epi16(__A, __B), @@ -2091,7 +2092,7 @@ _mm256_maskz_sra_epi16(__mmask16 __U, __m256i __A, __m128i __B) } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_mask_srai_epi16(__m128i __W, __mmask8 __U, __m128i __A, int __B) +_mm_mask_srai_epi16(__m128i __W, __mmask8 __U, __m128i __A, unsigned int __B) { return (__m128i)__builtin_ia32_selectw_128((__mmask8)__U, (__v8hi)_mm_srai_epi16(__A, __B), @@ -2099,7 +2100,7 @@ _mm_mask_srai_epi16(__m128i __W, __mmask8 __U, __m128i __A, int __B) } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_maskz_srai_epi16(__mmask8 __U, __m128i __A, int __B) +_mm_maskz_srai_epi16(__mmask8 __U, __m128i __A, unsigned int __B) { return (__m128i)__builtin_ia32_selectw_128((__mmask8)__U, (__v8hi)_mm_srai_epi16(__A, __B), @@ -2107,7 +2108,8 @@ _mm_maskz_srai_epi16(__mmask8 __U, __m128i __A, int __B) } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_mask_srai_epi16(__m256i __W, __mmask16 __U, __m256i __A, int __B) +_mm256_mask_srai_epi16(__m256i __W, __mmask16 __U, __m256i __A, + unsigned int __B) { return (__m256i)__builtin_ia32_selectw_256((__mmask16)__U, (__v16hi)_mm256_srai_epi16(__A, __B), @@ -2115,7 +2117,7 @@ _mm256_mask_srai_epi16(__m256i __W, __mmask16 __U, __m256i __A, int __B) } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_maskz_srai_epi16(__mmask16 __U, __m256i __A, int __B) +_mm256_maskz_srai_epi16(__mmask16 __U, __m256i __A, unsigned int __B) { return (__m256i)__builtin_ia32_selectw_256((__mmask16)__U, (__v16hi)_mm256_srai_epi16(__A, __B), diff --git a/clang/lib/Headers/avx512vlintrin.h b/clang/lib/Headers/avx512vlintrin.h index 9d1d791bb248d7..968c10efeac0ce 100644 --- a/clang/lib/Headers/avx512vlintrin.h +++ b/clang/lib/Headers/avx512vlintrin.h @@ -4522,7 +4522,7 @@ _mm256_maskz_sll_epi32(__mmask8 __U, __m256i __A, __m128i __B) } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_mask_slli_epi32(__m128i __W, __mmask8 __U, __m128i __A, int __B) +_mm_mask_slli_epi32(__m128i __W, __mmask8 __U, __m128i __A, unsigned int __B) { return (__m128i)__builtin_ia32_selectd_128((__mmask8)__U, (__v4si)_mm_slli_epi32(__A, __B), @@ -4530,7 +4530,7 @@ _mm_mask_slli_epi32(__m128i __W, __mmask8 __U, __m128i __A, int __B) } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_maskz_slli_epi32(__mmask8 __U, __m128i __A, int __B) +_mm_maskz_slli_epi32(__mmask8 __U, __m128i __A, unsigned int __B) { return (__m128i)__builtin_ia32_selectd_128((__mmask8)__U, (__v4si)_mm_slli_epi32(__A, __B), @@ -4538,7 +4538,7 @@ _mm_maskz_slli_epi32(__mmask8 __U, __m128i __A, int __B) } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_mask_slli_epi32(__m256i __W, __mmask8 __U, __m256i __A, int __B) +_mm256_mask_slli_epi32(__m256i __W, __mmask8 __U, __m256i __A, unsigned int __B) { return (__m256i)__builtin_ia32_selectd_256((__mmask8)__U, (__v8si)_mm256_slli_epi32(__A, __B), @@ -4546,7 +4546,7 @@ _mm256_mask_slli_epi32(__m256i __W, __mmask8 __U, __m256i __A, int __B) } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_maskz_slli_epi32(__mmask8 __U, __m256i __A, int __B) +_mm256_maskz_slli_epi32(__mmask8 __U, __m256i __A, unsigned int __B) { return (__m256i)__builtin_ia32_selectd_256((__mmask8)__U, (__v8si)_mm256_slli_epi32(__A, __B), @@ -4586,7 +4586,7 @@ _mm256_maskz_sll_epi64(__mmask8 __U, __m256i __A, __m128i __B) } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_mask_slli_epi64(__m128i __W, __mmask8 __U, __m128i __A, int __B) +_mm_mask_slli_epi64(__m128i __W, __mmask8 __U, __m128i __A, unsigned int __B) { return (__m128i)__builtin_ia32_selectq_128((__mmask8)__U, (__v2di)_mm_slli_epi64(__A, __B), @@ -4594,7 +4594,7 @@ _mm_mask_slli_epi64(__m128i __W, __mmask8 __U, __m128i __A, int __B) } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_maskz_slli_epi64(__mmask8 __U, __m128i __A, int __B) +_mm_maskz_slli_epi64(__mmask8 __U, __m128i __A, unsigned int __B) { return (__m128i)__builtin_ia32_selectq_128((__mmask8)__U, (__v2di)_mm_slli_epi64(__A, __B), @@ -4602,7 +4602,7 @@ _mm_maskz_slli_epi64(__mmask8 __U, __m128i __A, int __B) } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_mask_slli_epi64(__m256i __W, __mmask8 __U, __m256i __A, int __B) +_mm256_mask_slli_epi64(__m256i __W, __mmask8 __U, __m256i __A, unsigned int __B) { return (__m256i)__builtin_ia32_selectq_256((__mmask8)__U, (__v4di)_mm256_slli_epi64(__A, __B), @@ -4610,7 +4610,7 @@ _mm256_mask_slli_epi64(__m256i __W, __mmask8 __U, __m256i __A, int __B) } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_maskz_slli_epi64(__mmask8 __U, __m256i __A, int __B) +_mm256_maskz_slli_epi64(__mmask8 __U, __m256i __A, unsigned int __B) { return (__m256i)__builtin_ia32_selectq_256((__mmask8)__U, (__v4di)_mm256_slli_epi64(__A, __B), @@ -4866,7 +4866,7 @@ _mm256_maskz_srl_epi32(__mmask8 __U, __m256i __A, __m128i __B) } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_mask_srli_epi32(__m128i __W, __mmask8 __U, __m128i __A, int __B) +_mm_mask_srli_epi32(__m128i __W, __mmask8 __U, __m128i __A, unsigned int __B) { return (__m128i)__builtin_ia32_selectd_128((__mmask8)__U, (__v4si)_mm_srli_epi32(__A, __B), @@ -4874,7 +4874,7 @@ _mm_mask_srli_epi32(__m128i __W, __mmask8 __U, __m128i __A, int __B) } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_maskz_srli_epi32(__mmask8 __U, __m128i __A, int __B) +_mm_maskz_srli_epi32(__mmask8 __U, __m128i __A, unsigned int __B) { return (__m128i)__builtin_ia32_selectd_128((__mmask8)__U, (__v4si)_mm_srli_epi32(__A, __B), @@ -4882,7 +4882,7 @@ _mm_maskz_srli_epi32(__mmask8 __U, __m128i __A, int __B) } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_mask_srli_epi32(__m256i __W, __mmask8 __U, __m256i __A, int __B) +_mm256_mask_srli_epi32(__m256i __W, __mmask8 __U, __m256i __A, unsigned int __B) { return (__m256i)__builtin_ia32_selectd_256((__mmask8)__U, (__v8si)_mm256_srli_epi32(__A, __B), @@ -4890,7 +4890,7 @@ _mm256_mask_srli_epi32(__m256i __W, __mmask8 __U, __m256i __A, int __B) } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_maskz_srli_epi32(__mmask8 __U, __m256i __A, int __B) +_mm256_maskz_srli_epi32(__mmask8 __U, __m256i __A, unsigned int __B) { return (__m256i)__builtin_ia32_selectd_256((__mmask8)__U, (__v8si)_mm256_srli_epi32(__A, __B), @@ -4930,7 +4930,7 @@ _mm256_maskz_srl_epi64(__mmask8 __U, __m256i __A, __m128i __B) } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_mask_srli_epi64(__m128i __W, __mmask8 __U, __m128i __A, int __B) +_mm_mask_srli_epi64(__m128i __W, __mmask8 __U, __m128i __A, unsigned int __B) { return (__m128i)__builtin_ia32_selectq_128((__mmask8)__U, (__v2di)_mm_srli_epi64(__A, __B), @@ -4938,7 +4938,7 @@ _mm_mask_srli_epi64(__m128i __W, __mmask8 __U, __m128i __A, int __B) } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_maskz_srli_epi64(__mmask8 __U, __m128i __A, int __B) +_mm_maskz_srli_epi64(__mmask8 __U, __m128i __A, unsigned int __B) { return (__m128i)__builtin_ia32_selectq_128((__mmask8)__U, (__v2di)_mm_srli_epi64(__A, __B), @@ -4946,7 +4946,7 @@ _mm_maskz_srli_epi64(__mmask8 __U, __m128i __A, int __B) } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_mask_srli_epi64(__m256i __W, __mmask8 __U, __m256i __A, int __B) +_mm256_mask_srli_epi64(__m256i __W, __mmask8 __U, __m256i __A, unsigned int __B) { return (__m256i)__builtin_ia32_selectq_256((__mmask8)__U, (__v4di)_mm256_srli_epi64(__A, __B), @@ -4954,7 +4954,7 @@ _mm256_mask_srli_epi64(__m256i __W, __mmask8 __U, __m256i __A, int __B) } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_maskz_srli_epi64(__mmask8 __U, __m256i __A, int __B) +_mm256_maskz_srli_epi64(__mmask8 __U, __m256i __A, unsigned int __B) { return (__m256i)__builtin_ia32_selectq_256((__mmask8)__U, (__v4di)_mm256_srli_epi64(__A, __B), @@ -6405,7 +6405,7 @@ _mm256_maskz_sra_epi32(__mmask8 __U, __m256i __A, __m128i __B) } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_mask_srai_epi32(__m128i __W, __mmask8 __U, __m128i __A, int __B) +_mm_mask_srai_epi32(__m128i __W, __mmask8 __U, __m128i __A, unsigned int __B) { return (__m128i)__builtin_ia32_selectd_128((__mmask8)__U, (__v4si)_mm_srai_epi32(__A, __B), @@ -6413,7 +6413,7 @@ _mm_mask_srai_epi32(__m128i __W, __mmask8 __U, __m128i __A, int __B) } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_maskz_srai_epi32(__mmask8 __U, __m128i __A, int __B) +_mm_maskz_srai_epi32(__mmask8 __U, __m128i __A, unsigned int __B) { return (__m128i)__builtin_ia32_selectd_128((__mmask8)__U, (__v4si)_mm_srai_epi32(__A, __B), @@ -6421,7 +6421,7 @@ _mm_maskz_srai_epi32(__mmask8 __U, __m128i __A, int __B) } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_mask_srai_epi32(__m256i __W, __mmask8 __U, __m256i __A, int __B) +_mm256_mask_srai_epi32(__m256i __W, __mmask8 __U, __m256i __A, unsigned int __B) { return (__m256i)__builtin_ia32_selectd_256((__mmask8)__U, (__v8si)_mm256_srai_epi32(__A, __B), @@ -6429,7 +6429,7 @@ _mm256_mask_srai_epi32(__m256i __W, __mmask8 __U, __m256i __A, int __B) } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_maskz_srai_epi32(__mmask8 __U, __m256i __A, int __B) +_mm256_maskz_srai_epi32(__mmask8 __U, __m256i __A, unsigned int __B) { return (__m256i)__builtin_ia32_selectd_256((__mmask8)__U, (__v8si)_mm256_srai_epi32(__A, __B), @@ -6481,13 +6481,13 @@ _mm256_maskz_sra_epi64(__mmask8 __U, __m256i __A, __m128i __B) } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_srai_epi64(__m128i __A, int __imm) +_mm_srai_epi64(__m128i __A, unsigned int __imm) { return (__m128i)__builtin_ia32_psraqi128((__v2di)__A, __imm); } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_mask_srai_epi64(__m128i __W, __mmask8 __U, __m128i __A, int __imm) +_mm_mask_srai_epi64(__m128i __W, __mmask8 __U, __m128i __A, unsigned int __imm) { return (__m128i)__builtin_ia32_selectq_128((__mmask8)__U, \ (__v2di)_mm_srai_epi64(__A, __imm), \ @@ -6495,7 +6495,7 @@ _mm_mask_srai_epi64(__m128i __W, __mmask8 __U, __m128i __A, int __imm) } static __inline__ __m128i __DEFAULT_FN_ATTRS128 -_mm_maskz_srai_epi64(__mmask8 __U, __m128i __A, int __imm) +_mm_maskz_srai_epi64(__mmask8 __U, __m128i __A, unsigned int __imm) { return (__m128i)__builtin_ia32_selectq_128((__mmask8)__U, \ (__v2di)_mm_srai_epi64(__A, __imm), \ @@ -6503,13 +6503,14 @@ _mm_maskz_srai_epi64(__mmask8 __U, __m128i __A, int __imm) } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_srai_epi64(__m256i __A, int __imm) +_mm256_srai_epi64(__m256i __A, unsigned int __imm) { return (__m256i)__builtin_ia32_psraqi256((__v4di)__A, __imm); } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_mask_srai_epi64(__m256i __W, __mmask8 __U, __m256i __A, int __imm) +_mm256_mask_srai_epi64(__m256i __W, __mmask8 __U, __m256i __A, + unsigned int __imm) { return (__m256i)__builtin_ia32_selectq_256((__mmask8)__U, \ (__v4di)_mm256_srai_epi64(__A, __imm), \ @@ -6517,7 +6518,7 @@ _mm256_mask_srai_epi64(__m256i __W, __mmask8 __U, __m256i __A, int __imm) } static __inline__ __m256i __DEFAULT_FN_ATTRS256 -_mm256_maskz_srai_epi64(__mmask8 __U, __m256i __A, int __imm) +_mm256_maskz_srai_epi64(__mmask8 __U, __m256i __A, unsigned int __imm) { return (__m256i)__builtin_ia32_selectq_256((__mmask8)__U, \ (__v4di)_mm256_srai_epi64(__A, __imm), \ diff --git a/clang/lib/Index/IndexDecl.cpp b/clang/lib/Index/IndexDecl.cpp index 68160bc59eb6a9..2ba323e635753b 100644 --- a/clang/lib/Index/IndexDecl.cpp +++ b/clang/lib/Index/IndexDecl.cpp @@ -765,6 +765,9 @@ bool IndexingContext::indexTopLevelDecl(const Decl *D) { if (isa(D)) return true; // Wait for the objc container. + if (IndexOpts.ShouldTraverseDecl && !IndexOpts.ShouldTraverseDecl(D)) + return true; // skip + return indexDecl(D); } diff --git a/clang/lib/Index/IndexingAction.cpp b/clang/lib/Index/IndexingAction.cpp index 4f402135672c37..e698c07133a9c6 100644 --- a/clang/lib/Index/IndexingAction.cpp +++ b/clang/lib/Index/IndexingAction.cpp @@ -131,6 +131,21 @@ std::unique_ptr index::createIndexingASTConsumer( ShouldSkipFunctionBody); } +std::unique_ptr clang::index::createIndexingASTConsumer( + std::shared_ptr DataConsumer, + const IndexingOptions &Opts, std::shared_ptr PP) { + std::function ShouldSkipFunctionBody = [](const Decl *) { + return false; + }; + if (Opts.ShouldTraverseDecl) + ShouldSkipFunctionBody = + [ShouldTraverseDecl(Opts.ShouldTraverseDecl)](const Decl *D) { + return !ShouldTraverseDecl(D); + }; + return createIndexingASTConsumer(std::move(DataConsumer), Opts, std::move(PP), + std::move(ShouldSkipFunctionBody)); +} + std::unique_ptr index::createIndexingAction(std::shared_ptr DataConsumer, const IndexingOptions &Opts) { diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index bd40e6b991a5db..5161c7d06cdabf 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -2497,7 +2497,7 @@ OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) { /// in_reduction-clause | allocator-clause | allocate-clause | /// acq_rel-clause | acquire-clause | release-clause | relaxed-clause | /// depobj-clause | destroy-clause | detach-clause | inclusive-clause | -/// exclusive-clause | uses_allocators-clause +/// exclusive-clause | uses_allocators-clause | use_device_addr-clause /// OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, bool FirstClause) { @@ -2663,6 +2663,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_allocate: case OMPC_nontemporal: @@ -3581,6 +3582,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, /// 'from' '(' [ mapper '(' mapper-identifier ')' ':' ] list ')' /// use_device_ptr-clause: /// 'use_device_ptr' '(' list ')' +/// use_device_addr-clause: +/// 'use_device_addr' '(' list ')' /// is_device_ptr-clause: /// 'is_device_ptr' '(' list ')' /// allocate-clause: diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index a4fe90f79eb99a..fe4fcdd01301b3 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -2391,7 +2391,7 @@ static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr, return TC_NotApplicable; auto SrcPointeeType = SrcPtrType->getPointeeType(); auto DestPointeeType = DestPtrType->getPointeeType(); - if (!DestPtrType->isAddressSpaceOverlapping(*SrcPtrType)) { + if (!DestPointeeType.isAddressSpaceOverlapping(SrcPointeeType)) { msg = diag::err_bad_cxx_cast_addr_space_mismatch; return TC_Failed; } @@ -2434,9 +2434,9 @@ void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) { const PointerType *SrcPPtr = cast(SrcPtr); QualType DestPPointee = DestPPtr->getPointeeType(); QualType SrcPPointee = SrcPPtr->getPointeeType(); - if (Nested ? DestPPointee.getAddressSpace() != - SrcPPointee.getAddressSpace() - : !DestPPtr->isAddressSpaceOverlapping(*SrcPPtr)) { + if (Nested + ? DestPPointee.getAddressSpace() != SrcPPointee.getAddressSpace() + : !DestPPointee.isAddressSpaceOverlapping(SrcPPointee)) { Self.Diag(OpRange.getBegin(), DiagID) << SrcType << DestType << Sema::AA_Casting << SrcExpr.get()->getSourceRange(); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 74a4fd8a06de3a..6fe48c860864b7 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6885,18 +6885,34 @@ NamedDecl *Sema::ActOnVariableDeclarator( if (SC == SC_Static && CurContext->isRecord()) { if (const CXXRecordDecl *RD = dyn_cast(DC)) { - // C++ [class.static.data]p2: - // A static data member shall not be a direct member of an unnamed - // or local class - // FIXME: or of a (possibly indirectly) nested class thereof. - if (RD->isLocalClass()) { + // Walk up the enclosing DeclContexts to check for any that are + // incompatible with static data members. + const DeclContext *FunctionOrMethod = nullptr; + const CXXRecordDecl *AnonStruct = nullptr; + for (DeclContext *Ctxt = DC; Ctxt; Ctxt = Ctxt->getParent()) { + if (Ctxt->isFunctionOrMethod()) { + FunctionOrMethod = Ctxt; + break; + } + const CXXRecordDecl *ParentDecl = dyn_cast(Ctxt); + if (ParentDecl && !ParentDecl->getDeclName()) { + AnonStruct = ParentDecl; + break; + } + } + if (FunctionOrMethod) { + // C++ [class.static.data]p5: A local class shall not have static data + // members. Diag(D.getIdentifierLoc(), diag::err_static_data_member_not_allowed_in_local_class) << Name << RD->getDeclName() << RD->getTagKind(); - } else if (!RD->getDeclName()) { + } else if (AnonStruct) { + // C++ [class.static.data]p4: Unnamed classes and classes contained + // directly or indirectly within unnamed classes shall not contain + // static data members. Diag(D.getIdentifierLoc(), diag::err_static_data_member_not_allowed_in_anon_struct) - << Name << RD->getTagKind(); + << Name << AnonStruct->getTagKind(); Invalid = true; } else if (RD->isUnion()) { // C++98 [class.union]p1: If a union contains a static data member, diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 93e67ad2940ccc..261e69b440524f 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -10087,10 +10087,8 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc, if (isRHSPointer) RHSPointeeTy = RHSExpr->getType()->getPointeeType(); // if both are pointers check if operation is valid wrt address spaces - if (S.getLangOpts().OpenCL && isLHSPointer && isRHSPointer) { - const PointerType *lhsPtr = LHSExpr->getType()->castAs(); - const PointerType *rhsPtr = RHSExpr->getType()->castAs(); - if (!lhsPtr->isAddressSpaceOverlapping(*rhsPtr)) { + if (isLHSPointer && isRHSPointer) { + if (!LHSPointeeTy.isAddressSpaceOverlapping(RHSPointeeTy)) { S.Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) << LHSExpr->getType() << RHSExpr->getType() << 1 /*arithmetic op*/ @@ -11444,8 +11442,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, if (LCanPointeeTy != RCanPointeeTy) { // Treat NULL constant as a special case in OpenCL. if (getLangOpts().OpenCL && !LHSIsNull && !RHSIsNull) { - const PointerType *LHSPtr = LHSType->castAs(); - if (!LHSPtr->isAddressSpaceOverlapping(*RHSType->castAs())) { + if (!LCanPointeeTy.isAddressSpaceOverlapping(RCanPointeeTy)) { Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) << LHSType << RHSType << 0 /* comparison */ diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index e556969a786ab6..a60a047db0e7ae 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -5408,6 +5408,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_nontemporal: case OMPC_order: @@ -10165,12 +10166,18 @@ StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef Clauses, assert(isa(AStmt) && "Captured statement expected"); - // OpenMP [2.10.1, Restrictions, p. 97] - // At least one map clause must appear on the directive. - if (!hasClauses(Clauses, OMPC_map, OMPC_use_device_ptr)) { + // OpenMP [2.12.2, target data Construct, Restrictions] + // At least one map, use_device_addr or use_device_ptr clause must appear on + // the directive. + if (!hasClauses(Clauses, OMPC_map, OMPC_use_device_ptr) && + (LangOpts.OpenMP < 50 || !hasClauses(Clauses, OMPC_use_device_addr))) { + StringRef Expected; + if (LangOpts.OpenMP < 50) + Expected = "'map' or 'use_device_ptr'"; + else + Expected = "'map', 'use_device_ptr', or 'use_device_addr'"; Diag(StartLoc, diag::err_omp_no_clause_for_directive) - << "'map' or 'use_device_ptr'" - << getOpenMPDirectiveName(OMPD_target_data); + << Expected << getOpenMPDirectiveName(OMPD_target_data); return StmtError(); } @@ -11535,6 +11542,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_unified_address: case OMPC_unified_shared_memory: @@ -12289,6 +12297,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_unified_address: case OMPC_unified_shared_memory: @@ -12731,6 +12740,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_unified_address: case OMPC_unified_shared_memory: @@ -12956,6 +12966,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_unified_address: case OMPC_unified_shared_memory: @@ -13195,6 +13206,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_atomic_default_mem_order: case OMPC_device_type: @@ -13406,6 +13418,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_use_device_ptr: Res = ActOnOpenMPUseDevicePtrClause(VarList, Locs); break; + case OMPC_use_device_addr: + Res = ActOnOpenMPUseDeviceAddrClause(VarList, Locs); + break; case OMPC_is_device_ptr: Res = ActOnOpenMPIsDevicePtrClause(VarList, Locs); break; @@ -18389,6 +18404,54 @@ OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef VarList, MVLI.VarBaseDeclarations, MVLI.VarComponents); } +OMPClause *Sema::ActOnOpenMPUseDeviceAddrClause(ArrayRef VarList, + const OMPVarListLocTy &Locs) { + MappableVarListInfo MVLI(VarList); + + for (Expr *RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP use_device_addr clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/true); + if (Res.second) { + // It will be analyzed later. + MVLI.ProcessedVarList.push_back(RefExpr); + } + ValueDecl *D = Res.first; + if (!D) + continue; + auto *VD = dyn_cast(D); + + // If required, build a capture to implement the privatization initialized + // with the current list item value. + DeclRefExpr *Ref = nullptr; + if (!VD) + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); + MVLI.ProcessedVarList.push_back(VD ? RefExpr->IgnoreParens() : Ref); + + // We need to add a data sharing attribute for this variable to make sure it + // is correctly captured. A variable that shows up in a use_device_addr has + // similar properties of a first private variable. + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref); + + // Create a mappable component for the list item. List items in this clause + // only need a component. + MVLI.VarBaseDeclarations.push_back(D); + MVLI.VarComponents.emplace_back(); + MVLI.VarComponents.back().push_back( + OMPClauseMappableExprCommon::MappableComponent(SimpleRefExpr, D)); + } + + if (MVLI.ProcessedVarList.empty()) + return nullptr; + + return OMPUseDeviceAddrClause::Create(Context, Locs, MVLI.ProcessedVarList, + MVLI.VarBaseDeclarations, + MVLI.VarComponents); +} + OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef VarList, const OMPVarListLocTy &Locs) { MappableVarListInfo MVLI(VarList); diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 3d91893b40650a..e9d3c755eb232a 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/EvaluatedExprVisitor.h" #include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" @@ -170,6 +171,44 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A, return LoopHintAttr::CreateImplicit(S.Context, Option, State, ValueExpr, A); } +namespace { +class CallExprFinder : public ConstEvaluatedExprVisitor { + bool FoundCallExpr = false; + +public: + typedef ConstEvaluatedExprVisitor Inherited; + + CallExprFinder(Sema &S, const Stmt *St) : Inherited(S.Context) { Visit(St); } + + bool foundCallExpr() { return FoundCallExpr; } + + void VisitCallExpr(const CallExpr *E) { FoundCallExpr = true; } + + void Visit(const Stmt *St) { + if (!St) + return; + ConstEvaluatedExprVisitor::Visit(St); + } +}; +} // namespace + +static Attr *handleNoMergeAttr(Sema &S, Stmt *St, const ParsedAttr &A, + SourceRange Range) { + NoMergeAttr NMA(S.Context, A); + if (S.CheckAttrNoArgs(A)) + return nullptr; + + CallExprFinder CEF(S, St); + + if (!CEF.foundCallExpr()) { + S.Diag(St->getBeginLoc(), diag::warn_nomerge_attribute_ignored_in_stmt) + << NMA.getSpelling(); + return nullptr; + } + + return ::new (S.Context) NoMergeAttr(S.Context, A); +} + static void CheckForIncompatibleAttributes(Sema &S, const SmallVectorImpl &Attrs) { @@ -335,6 +374,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, return handleOpenCLUnrollHint(S, St, A, Range); case ParsedAttr::AT_Suppress: return handleSuppressAttr(S, St, A, Range); + case ParsedAttr::AT_NoMerge: + return handleNoMergeAttr(S, St, A, Range); default: // if we're here, then we parsed a known attribute, but didn't recognize // it as a statement attribute => it is declaration attribute diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 923792fde7fcbb..e4c71552f718fb 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2036,6 +2036,15 @@ class TreeTransform { return getSema().ActOnOpenMPUseDevicePtrClause(VarList, Locs); } + /// Build a new OpenMP 'use_device_addr' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPUseDeviceAddrClause(ArrayRef VarList, + const OMPVarListLocTy &Locs) { + return getSema().ActOnOpenMPUseDeviceAddrClause(VarList, Locs); + } + /// Build a new OpenMP 'is_device_ptr' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. @@ -9740,6 +9749,21 @@ OMPClause *TreeTransform::TransformOMPUseDevicePtrClause( return getDerived().RebuildOMPUseDevicePtrClause(Vars, Locs); } +template +OMPClause *TreeTransform::TransformOMPUseDeviceAddrClause( + OMPUseDeviceAddrClause *C) { + llvm::SmallVector Vars; + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = getDerived().TransformExpr(cast(VE)); + if (EVar.isInvalid()) + return nullptr; + Vars.push_back(EVar.get()); + } + OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); + return getDerived().RebuildOMPUseDeviceAddrClause(Vars, Locs); +} + template OMPClause * TreeTransform::TransformOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 16bcb18f4e68ec..a5a1276253c7c2 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -11918,6 +11918,15 @@ OMPClause *OMPClauseReader::readClause() { C = OMPUseDevicePtrClause::CreateEmpty(Context, Sizes); break; } + case llvm::omp::OMPC_use_device_addr: { + OMPMappableExprListSizeTy Sizes; + Sizes.NumVars = Record.readInt(); + Sizes.NumUniqueDeclarations = Record.readInt(); + Sizes.NumComponentLists = Record.readInt(); + Sizes.NumComponents = Record.readInt(); + C = OMPUseDeviceAddrClause::CreateEmpty(Context, Sizes); + break; + } case llvm::omp::OMPC_is_device_ptr: { OMPMappableExprListSizeTy Sizes; Sizes.NumVars = Record.readInt(); @@ -12704,6 +12713,48 @@ void OMPClauseReader::VisitOMPUseDevicePtrClause(OMPUseDevicePtrClause *C) { C->setComponents(Components, ListSizes); } +void OMPClauseReader::VisitOMPUseDeviceAddrClause(OMPUseDeviceAddrClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + auto NumVars = C->varlist_size(); + auto UniqueDecls = C->getUniqueDeclarationsNum(); + auto TotalLists = C->getTotalComponentListNum(); + auto TotalComponents = C->getTotalComponentsNum(); + + SmallVector Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); + + SmallVector Decls; + Decls.reserve(UniqueDecls); + for (unsigned i = 0; i < UniqueDecls; ++i) + Decls.push_back(Record.readDeclAs()); + C->setUniqueDecls(Decls); + + SmallVector ListsPerDecl; + ListsPerDecl.reserve(UniqueDecls); + for (unsigned i = 0; i < UniqueDecls; ++i) + ListsPerDecl.push_back(Record.readInt()); + C->setDeclNumLists(ListsPerDecl); + + SmallVector ListSizes; + ListSizes.reserve(TotalLists); + for (unsigned i = 0; i < TotalLists; ++i) + ListSizes.push_back(Record.readInt()); + C->setComponentListSizes(ListSizes); + + SmallVector Components; + Components.reserve(TotalComponents); + for (unsigned i = 0; i < TotalComponents; ++i) { + Expr *AssociatedExpr = Record.readSubExpr(); + auto *AssociatedDecl = Record.readDeclAs(); + Components.push_back(OMPClauseMappableExprCommon::MappableComponent( + AssociatedExpr, AssociatedDecl)); + } + C->setComponents(Components, ListSizes); +} + void OMPClauseReader::VisitOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) { C->setLParenLoc(Record.readSourceLocation()); auto NumVars = C->varlist_size(); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 1e3adb588da29b..9d81e137f0bb8e 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -6625,6 +6625,26 @@ void OMPClauseWriter::VisitOMPUseDevicePtrClause(OMPUseDevicePtrClause *C) { } } +void OMPClauseWriter::VisitOMPUseDeviceAddrClause(OMPUseDeviceAddrClause *C) { + Record.push_back(C->varlist_size()); + Record.push_back(C->getUniqueDeclarationsNum()); + Record.push_back(C->getTotalComponentListNum()); + Record.push_back(C->getTotalComponentsNum()); + Record.AddSourceLocation(C->getLParenLoc()); + for (auto *E : C->varlists()) + Record.AddStmt(E); + for (auto *D : C->all_decls()) + Record.AddDeclRef(D); + for (auto N : C->all_num_lists()) + Record.push_back(N); + for (auto N : C->all_lists_sizes()) + Record.push_back(N); + for (auto &M : C->all_components()) { + Record.AddStmt(M.getAssociatedExpression()); + Record.AddDeclRef(M.getAssociatedDeclaration()); + } +} + void OMPClauseWriter::VisitOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) { Record.push_back(C->varlist_size()); Record.push_back(C->getUniqueDeclarationsNum()); diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt index bcf2dfdb832661..4f885fadf4158d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -121,6 +121,8 @@ add_clang_library(clangStaticAnalyzerCheckers VLASizeChecker.cpp ValistChecker.cpp VirtualCallChecker.cpp + WebKit/PtrTypesSemantics.cpp + WebKit/RefCntblBaseVirtualDtorChecker.cpp LINK_LIBS clangAST diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 7fae3a62211d84..fa69bc253fbd05 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -445,7 +445,7 @@ class MallocChecker /// Perform a zero-allocation check. /// - /// \param [in] E The expression that allocates memory. + /// \param [in] Call The expression that allocates memory. /// \param [in] IndexOfSizeArg Index of the argument that specifies the size /// of the memory that needs to be allocated. E.g. for malloc, this would be /// 0. @@ -469,7 +469,7 @@ class MallocChecker /// - first: name of the resource (e.g. 'malloc') /// - (OPTIONAL) second: size of the allocated region /// - /// \param [in] CE The expression that allocates memory. + /// \param [in] Call The expression that allocates memory. /// \param [in] Att The ownership_returns attribute. /// \param [in] State The \c ProgramState right before allocation. /// \returns The ProgramState right after allocation. @@ -480,7 +480,7 @@ class MallocChecker /// Models memory allocation. /// - /// \param [in] CE The expression that allocates memory. + /// \param [in] Call The expression that allocates memory. /// \param [in] SizeEx Size of the memory that needs to be allocated. /// \param [in] Init The value the allocated memory needs to be initialized. /// with. For example, \c calloc initializes the allocated memory to 0, @@ -495,7 +495,7 @@ class MallocChecker /// Models memory allocation. /// - /// \param [in] CE The expression that allocates memory. + /// \param [in] Call The expression that allocates memory. /// \param [in] Size Size of the memory that needs to be allocated. /// \param [in] Init The value the allocated memory needs to be initialized. /// with. For example, \c calloc initializes the allocated memory to 0, @@ -532,7 +532,7 @@ class MallocChecker /// - first: name of the resource (e.g. 'malloc') /// - second: index of the parameter the attribute applies to /// - /// \param [in] CE The expression that frees memory. + /// \param [in] Call The expression that frees memory. /// \param [in] Att The ownership_takes or ownership_holds attribute. /// \param [in] State The \c ProgramState right before allocation. /// \returns The ProgramState right after deallocation. @@ -543,7 +543,7 @@ class MallocChecker /// Models memory deallocation. /// - /// \param [in] CE The expression that frees memory. + /// \param [in] Call The expression that frees memory. /// \param [in] State The \c ProgramState right before allocation. /// \param [in] Num Index of the argument that needs to be freed. This is /// normally 0, but for custom free functions it may be different. @@ -570,7 +570,7 @@ class MallocChecker /// Models memory deallocation. /// /// \param [in] ArgExpr The variable who's pointee needs to be freed. - /// \param [in] ParentExpr The expression that frees the memory. + /// \param [in] Call The expression that frees the memory. /// \param [in] State The \c ProgramState right before allocation. /// normally 0, but for custom free functions it may be different. /// \param [in] Hold Whether the parameter at \p Index has the ownership_holds @@ -599,7 +599,7 @@ class MallocChecker // /// Models memory reallocation. /// - /// \param [in] CE The expression that reallocated memory + /// \param [in] Call The expression that reallocated memory /// \param [in] ShouldFreeOnFail Whether if reallocation fails, the supplied /// memory should be freed. /// \param [in] State The \c ProgramState right before reallocation. @@ -623,7 +623,7 @@ class MallocChecker /// Models zero initialized array allocation. /// - /// \param [in] CE The expression that reallocated memory + /// \param [in] Call The expression that reallocated memory /// \param [in] State The \c ProgramState right before reallocation. /// \returns The ProgramState right after allocation. LLVM_NODISCARD @@ -684,41 +684,42 @@ class MallocChecker static bool SummarizeValue(raw_ostream &os, SVal V); static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR); - void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange Range, - const Expr *DeallocExpr, AllocationFamily Family) const; + void HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal, SourceRange Range, + const Expr *DeallocExpr, + AllocationFamily Family) const; - void ReportFreeAlloca(CheckerContext &C, SVal ArgVal, + void HandleFreeAlloca(CheckerContext &C, SVal ArgVal, SourceRange Range) const; - void ReportMismatchedDealloc(CheckerContext &C, SourceRange Range, + void HandleMismatchedDealloc(CheckerContext &C, SourceRange Range, const Expr *DeallocExpr, const RefState *RS, SymbolRef Sym, bool OwnershipTransferred) const; - void ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range, + void HandleOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range, const Expr *DeallocExpr, AllocationFamily Family, const Expr *AllocExpr = nullptr) const; - void ReportUseAfterFree(CheckerContext &C, SourceRange Range, + void HandleUseAfterFree(CheckerContext &C, SourceRange Range, SymbolRef Sym) const; - void ReportDoubleFree(CheckerContext &C, SourceRange Range, bool Released, + void HandleDoubleFree(CheckerContext &C, SourceRange Range, bool Released, SymbolRef Sym, SymbolRef PrevSym) const; - void ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const; + void HandleDoubleDelete(CheckerContext &C, SymbolRef Sym) const; - void ReportUseZeroAllocated(CheckerContext &C, SourceRange Range, - SymbolRef Sym) const; + void HandleUseZeroAlloc(CheckerContext &C, SourceRange Range, + SymbolRef Sym) const; - void ReportFunctionPointerFree(CheckerContext &C, SVal ArgVal, - SourceRange Range, const Expr *FreeExpr, - AllocationFamily Family) const; + void HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal, SourceRange Range, + const Expr *FreeExpr, + AllocationFamily Family) const; /// Find the location of the allocation for Sym on the path leading to the /// exploded node N. static LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym, CheckerContext &C); - void reportLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const; + void HandleLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const; /// Test if value in ArgVal equals to value in macro `ZERO_SIZE_PTR`. bool isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C, @@ -1743,6 +1744,15 @@ ProgramStateRef MallocChecker::FreeMemAux( const MemRegion *R = ArgVal.getAsRegion(); const Expr *ParentExpr = Call.getOriginExpr(); + // NOTE: We detected a bug, but the checker under whose name we would emit the + // error could be disabled. Generally speaking, the MallocChecker family is an + // integral part of the Static Analyzer, and disabling any part of it should + // only be done under exceptional circumstances, such as frequent false + // positives. If this is the case, we can reasonably believe that there are + // serious faults in our understanding of the source code, and even if we + // don't emit an warning, we should terminate further analysis with a sink + // node. + // Nonlocs can't be freed, of course. // Non-region locations (labels and fixed addresses) also shouldn't be freed. if (!R) { @@ -1752,7 +1762,8 @@ ProgramStateRef MallocChecker::FreeMemAux( // zero-sized memory block which is allowed to be freed, despite not being a // null pointer. if (Family != AF_Malloc || !isArgZERO_SIZE_PTR(State, C, ArgVal)) - ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, Family); + HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, + Family); return nullptr; } @@ -1760,7 +1771,8 @@ ProgramStateRef MallocChecker::FreeMemAux( // Blocks might show up as heap data, but should not be free()d if (isa(R)) { - ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, Family); + HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, + Family); return nullptr; } @@ -1778,9 +1790,10 @@ ProgramStateRef MallocChecker::FreeMemAux( // False negatives are better than false positives. if (isa(R)) - ReportFreeAlloca(C, ArgVal, ArgExpr->getSourceRange()); + HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange()); else - ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, Family); + HandleNonHeapDealloc(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, + Family); return nullptr; } @@ -1802,14 +1815,14 @@ ProgramStateRef MallocChecker::FreeMemAux( // Memory returned by alloca() shouldn't be freed. if (RsBase->getAllocationFamily() == AF_Alloca) { - ReportFreeAlloca(C, ArgVal, ArgExpr->getSourceRange()); + HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange()); return nullptr; } // Check for double free first. if ((RsBase->isReleased() || RsBase->isRelinquished()) && !didPreviousFreeFail(State, SymBase, PreviousRetStatusSymbol)) { - ReportDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(), + HandleDoubleFree(C, ParentExpr->getSourceRange(), RsBase->isReleased(), SymBase, PreviousRetStatusSymbol); return nullptr; @@ -1821,8 +1834,8 @@ ProgramStateRef MallocChecker::FreeMemAux( // Check if an expected deallocation function matches the real one. bool DeallocMatchesAlloc = RsBase->getAllocationFamily() == Family; if (!DeallocMatchesAlloc) { - ReportMismatchedDealloc(C, ArgExpr->getSourceRange(), - ParentExpr, RsBase, SymBase, Hold); + HandleMismatchedDealloc(C, ArgExpr->getSourceRange(), ParentExpr, + RsBase, SymBase, Hold); return nullptr; } @@ -1833,7 +1846,7 @@ ProgramStateRef MallocChecker::FreeMemAux( !Offset.hasSymbolicOffset() && Offset.getOffset() != 0) { const Expr *AllocExpr = cast(RsBase->getStmt()); - ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, + HandleOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, Family, AllocExpr); return nullptr; } @@ -1841,8 +1854,8 @@ ProgramStateRef MallocChecker::FreeMemAux( } if (SymBase->getType()->isFunctionPointerType()) { - ReportFunctionPointerFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, - Family); + HandleFunctionPtrFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, + Family); return nullptr; } @@ -2009,13 +2022,15 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os, } } -void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, - SourceRange Range, const Expr *DeallocExpr, - AllocationFamily Family) const { +void MallocChecker::HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal, + SourceRange Range, + const Expr *DeallocExpr, + AllocationFamily Family) const { - if (!ChecksEnabled[CK_MallocChecker] && - !ChecksEnabled[CK_NewDeleteChecker]) + if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) { + C.addSink(); return; + } Optional CheckKind = getCheckIfTracked(Family); if (!CheckKind.hasValue()) @@ -2055,7 +2070,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, } } -void MallocChecker::ReportFreeAlloca(CheckerContext &C, SVal ArgVal, +void MallocChecker::HandleFreeAlloca(CheckerContext &C, SVal ArgVal, SourceRange Range) const { Optional CheckKind; @@ -2064,8 +2079,10 @@ void MallocChecker::ReportFreeAlloca(CheckerContext &C, SVal ArgVal, CheckKind = CK_MallocChecker; else if (ChecksEnabled[CK_MismatchedDeallocatorChecker]) CheckKind = CK_MismatchedDeallocatorChecker; - else + else { + C.addSink(); return; + } if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_FreeAlloca[*CheckKind]) @@ -2081,15 +2098,16 @@ void MallocChecker::ReportFreeAlloca(CheckerContext &C, SVal ArgVal, } } -void MallocChecker::ReportMismatchedDealloc(CheckerContext &C, +void MallocChecker::HandleMismatchedDealloc(CheckerContext &C, SourceRange Range, const Expr *DeallocExpr, - const RefState *RS, - SymbolRef Sym, + const RefState *RS, SymbolRef Sym, bool OwnershipTransferred) const { - if (!ChecksEnabled[CK_MismatchedDeallocatorChecker]) + if (!ChecksEnabled[CK_MismatchedDeallocatorChecker]) { + C.addSink(); return; + } if (ExplodedNode *N = C.generateErrorNode()) { if (!BT_MismatchedDealloc) @@ -2137,14 +2155,15 @@ void MallocChecker::ReportMismatchedDealloc(CheckerContext &C, } } -void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal, +void MallocChecker::HandleOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range, const Expr *DeallocExpr, AllocationFamily Family, const Expr *AllocExpr) const { - if (!ChecksEnabled[CK_MallocChecker] && - !ChecksEnabled[CK_NewDeleteChecker]) + if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) { + C.addSink(); return; + } Optional CheckKind = getCheckIfTracked(Family); if (!CheckKind.hasValue()) @@ -2194,13 +2213,14 @@ void MallocChecker::ReportOffsetFree(CheckerContext &C, SVal ArgVal, C.emitReport(std::move(R)); } -void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range, +void MallocChecker::HandleUseAfterFree(CheckerContext &C, SourceRange Range, SymbolRef Sym) const { - if (!ChecksEnabled[CK_MallocChecker] && - !ChecksEnabled[CK_NewDeleteChecker] && - !ChecksEnabled[CK_InnerPointerChecker]) + if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker] && + !ChecksEnabled[CK_InnerPointerChecker]) { + C.addSink(); return; + } Optional CheckKind = getCheckIfTracked(C, Sym); if (!CheckKind.hasValue()) @@ -2232,13 +2252,14 @@ void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range, } } -void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range, +void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range, bool Released, SymbolRef Sym, SymbolRef PrevSym) const { - if (!ChecksEnabled[CK_MallocChecker] && - !ChecksEnabled[CK_NewDeleteChecker]) + if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) { + C.addSink(); return; + } Optional CheckKind = getCheckIfTracked(C, Sym); if (!CheckKind.hasValue()) @@ -2263,10 +2284,12 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range, } } -void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const { +void MallocChecker::HandleDoubleDelete(CheckerContext &C, SymbolRef Sym) const { - if (!ChecksEnabled[CK_NewDeleteChecker]) + if (!ChecksEnabled[CK_NewDeleteChecker]) { + C.addSink(); return; + } Optional CheckKind = getCheckIfTracked(C, Sym); if (!CheckKind.hasValue()) @@ -2287,13 +2310,13 @@ void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const { } } -void MallocChecker::ReportUseZeroAllocated(CheckerContext &C, - SourceRange Range, - SymbolRef Sym) const { +void MallocChecker::HandleUseZeroAlloc(CheckerContext &C, SourceRange Range, + SymbolRef Sym) const { - if (!ChecksEnabled[CK_MallocChecker] && - !ChecksEnabled[CK_NewDeleteChecker]) + if (!ChecksEnabled[CK_MallocChecker] && !ChecksEnabled[CK_NewDeleteChecker]) { + C.addSink(); return; + } Optional CheckKind = getCheckIfTracked(C, Sym); @@ -2318,12 +2341,14 @@ void MallocChecker::ReportUseZeroAllocated(CheckerContext &C, } } -void MallocChecker::ReportFunctionPointerFree(CheckerContext &C, SVal ArgVal, - SourceRange Range, - const Expr *FreeExpr, - AllocationFamily Family) const { - if (!ChecksEnabled[CK_MallocChecker]) +void MallocChecker::HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal, + SourceRange Range, + const Expr *FreeExpr, + AllocationFamily Family) const { + if (!ChecksEnabled[CK_MallocChecker]) { + C.addSink(); return; + } Optional CheckKind = getCheckIfTracked(Family); if (!CheckKind.hasValue()) @@ -2521,7 +2546,7 @@ MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N, return LeakInfo(AllocNode, ReferenceRegion); } -void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N, +void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N, CheckerContext &C) const { if (!ChecksEnabled[CK_MallocChecker] && @@ -2637,7 +2662,7 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, if (N) { for (SmallVectorImpl::iterator I = Errors.begin(), E = Errors.end(); I != E; ++I) { - reportLeak(*I, N, C); + HandleLeak(*I, N, C); } } } @@ -2822,7 +2847,7 @@ bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const { if (isReleased(Sym, C)) { - ReportUseAfterFree(C, S->getSourceRange(), Sym); + HandleUseAfterFree(C, S->getSourceRange(), Sym); return true; } @@ -2835,17 +2860,17 @@ void MallocChecker::checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C, if (const RefState *RS = C.getState()->get(Sym)) { if (RS->isAllocatedOfSizeZero()) - ReportUseZeroAllocated(C, RS->getStmt()->getSourceRange(), Sym); + HandleUseZeroAlloc(C, RS->getStmt()->getSourceRange(), Sym); } else if (C.getState()->contains(Sym)) { - ReportUseZeroAllocated(C, S->getSourceRange(), Sym); + HandleUseZeroAlloc(C, S->getSourceRange(), Sym); } } bool MallocChecker::checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const { if (isReleased(Sym, C)) { - ReportDoubleDelete(C, Sym); + HandleDoubleDelete(C, Sym); return true; } return false; diff --git a/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp index df69254ead2634..abeca596d056b3 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp @@ -338,7 +338,7 @@ void NumberObjectConversionChecker::checkASTCodeBody(const Decl *D, MatchFinder F; Callback CB(this, BR, AM.getAnalysisDeclContext(D)); - F.addMatcher(stmt(forEachDescendant(FinalM)), &CB); + F.addMatcher(traverse(TK_AsIs, stmt(forEachDescendant(FinalM))), &CB); F.match(*D->getBody(), AM.getASTContext()); } diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp index 8eee4df473e8f9..25d87f4acfc910 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerSortingChecker.cpp @@ -86,8 +86,9 @@ auto matchSortWithPointers() -> decltype(decl()) { ))) )))); - auto PointerSortM = stmt(callExpr(allOf(SortFuncM, IteratesPointerEltsM)) - ).bind(WarnAtNode); + auto PointerSortM = traverse( + TK_AsIs, + stmt(callExpr(allOf(SortFuncM, IteratesPointerEltsM))).bind(WarnAtNode)); return decl(forEachDescendant(PointerSortM)); } diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp index 4bf9beb365f666..3f3267ff93916d 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp @@ -12,12 +12,12 @@ //===----------------------------------------------------------------------===// #include "RetainCountChecker.h" +#include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" using namespace clang; using namespace ento; using namespace retaincountchecker; -using llvm::StrInStrNoCase; REGISTER_MAP_WITH_PROGRAMSTATE(RefBindings, SymbolRef, RefVal) @@ -701,7 +701,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ, for (ProgramStateRef St : Out) { if (DeallocSent) { - C.addTransition(St, C.getPredecessor(), &DeallocSentTag); + C.addTransition(St, C.getPredecessor(), &getDeallocSentTag()); } else { C.addTransition(St); } @@ -844,13 +844,13 @@ RetainCountChecker::errorKindToBugKind(RefVal::Kind ErrorKind, SymbolRef Sym) const { switch (ErrorKind) { case RefVal::ErrorUseAfterRelease: - return useAfterRelease; + return *UseAfterRelease; case RefVal::ErrorReleaseNotOwned: - return releaseNotOwned; + return *ReleaseNotOwned; case RefVal::ErrorDeallocNotOwned: if (Sym->getType()->getPointeeCXXRecordDecl()) - return freeNotOwned; - return deallocNotOwned; + return *FreeNotOwned; + return *DeallocNotOwned; default: llvm_unreachable("Unhandled error."); } @@ -946,7 +946,7 @@ bool RetainCountChecker::evalCall(const CallEvent &Call, // Assume that output is zero on the other branch. NullOutputState = NullOutputState->BindExpr( CE, LCtx, C.getSValBuilder().makeNull(), /*Invalidate=*/false); - C.addTransition(NullOutputState, &CastFailTag); + C.addTransition(NullOutputState, &getCastFailTag()); // And on the original branch assume that both input and // output are non-zero. @@ -1095,7 +1095,7 @@ ExplodedNode * RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, if (N) { const LangOptions &LOpts = C.getASTContext().getLangOpts(); auto R = - std::make_unique(leakAtReturn, LOpts, N, Sym, C); + std::make_unique(*LeakAtReturn, LOpts, N, Sym, C); C.emitReport(std::move(R)); } return N; @@ -1120,7 +1120,7 @@ ExplodedNode * RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, ExplodedNode *N = C.addTransition(state, Pred, &ReturnNotOwnedTag); if (N) { auto R = std::make_unique( - returnNotOwnedForOwned, C.getASTContext().getLangOpts(), N, Sym); + *ReturnNotOwnedForOwned, C.getASTContext().getLangOpts(), N, Sym); C.emitReport(std::move(R)); } return N; @@ -1273,8 +1273,8 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state, os << "has a +" << V.getCount() << " retain count"; const LangOptions &LOpts = Ctx.getASTContext().getLangOpts(); - auto R = std::make_unique(overAutorelease, LOpts, N, Sym, - os.str()); + auto R = std::make_unique(*OverAutorelease, LOpts, N, Sym, + os.str()); Ctx.emitReport(std::move(R)); } @@ -1320,7 +1320,7 @@ RetainCountChecker::processLeaks(ProgramStateRef state, if (N) { for (SymbolRef L : Leaked) { - const RefCountBug &BT = Pred ? leakWithinFunction : leakAtReturn; + const RefCountBug &BT = Pred ? *LeakWithinFunction : *LeakAtReturn; Ctx.emitReport(std::make_unique(BT, LOpts, N, L, Ctx)); } } @@ -1473,34 +1473,39 @@ void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State, // Checker registration. //===----------------------------------------------------------------------===// +std::unique_ptr RetainCountChecker::DeallocSentTag; +std::unique_ptr RetainCountChecker::CastFailTag; + void ento::registerRetainCountBase(CheckerManager &Mgr) { - Mgr.registerChecker(); + auto *Chk = Mgr.registerChecker(); + Chk->DeallocSentTag = + std::make_unique(Chk, "DeallocSent"); + Chk->CastFailTag = + std::make_unique(Chk, "DynamicCastFail"); } bool ento::shouldRegisterRetainCountBase(const CheckerManager &mgr) { return true; } - -// FIXME: remove this, hack for backwards compatibility: -// it should be possible to enable the NS/CF retain count checker as -// osx.cocoa.RetainCount, and it should be possible to disable -// osx.OSObjectRetainCount using osx.cocoa.RetainCount:CheckOSObject=false. -static bool getOption(const AnalyzerOptions &Options, - StringRef Postfix, - StringRef Value) { - auto I = Options.Config.find( - (StringRef("osx.cocoa.RetainCount:") + Postfix).str()); - if (I != Options.Config.end()) - return I->getValue() == Value; - return false; -} - void ento::registerRetainCountChecker(CheckerManager &Mgr) { auto *Chk = Mgr.getChecker(); Chk->TrackObjCAndCFObjects = true; - Chk->TrackNSCFStartParam = getOption(Mgr.getAnalyzerOptions(), - "TrackNSCFStartParam", - "true"); + Chk->TrackNSCFStartParam = Mgr.getAnalyzerOptions().getCheckerBooleanOption( + Mgr.getCurrentCheckerName(), "TrackNSCFStartParam"); + +#define INIT_BUGTYPE(KIND) \ + Chk->KIND = std::make_unique(Mgr.getCurrentCheckerName(), \ + RefCountBug::KIND); + // TODO: Ideally, we should have a checker for each of these bug types. + INIT_BUGTYPE(UseAfterRelease) + INIT_BUGTYPE(ReleaseNotOwned) + INIT_BUGTYPE(DeallocNotOwned) + INIT_BUGTYPE(FreeNotOwned) + INIT_BUGTYPE(OverAutorelease) + INIT_BUGTYPE(ReturnNotOwnedForOwned) + INIT_BUGTYPE(LeakWithinFunction) + INIT_BUGTYPE(LeakAtReturn) +#undef INIT_BUGTYPE } bool ento::shouldRegisterRetainCountChecker(const CheckerManager &mgr) { @@ -1509,10 +1514,30 @@ bool ento::shouldRegisterRetainCountChecker(const CheckerManager &mgr) { void ento::registerOSObjectRetainCountChecker(CheckerManager &Mgr) { auto *Chk = Mgr.getChecker(); - if (!getOption(Mgr.getAnalyzerOptions(), - "CheckOSObject", - "false")) - Chk->TrackOSObjects = true; + Chk->TrackOSObjects = true; + + // FIXME: We want bug reports to always have the same checker name associated + // with them, yet here, if RetainCountChecker is disabled but + // OSObjectRetainCountChecker is enabled, the checker names will be different. + // This hack will make it so that the checker name depends on which checker is + // enabled rather than on the registration order. + // For the most part, we want **non-hidden checkers** to be associated with + // diagnostics, and **hidden checker options** with the fine-tuning of + // modeling. Following this logic, OSObjectRetainCountChecker should be the + // latter, but we can't just remove it for backward compatibility reasons. +#define LAZY_INIT_BUGTYPE(KIND) \ + if (!Chk->KIND) \ + Chk->KIND = std::make_unique(Mgr.getCurrentCheckerName(), \ + RefCountBug::KIND); + LAZY_INIT_BUGTYPE(UseAfterRelease) + LAZY_INIT_BUGTYPE(ReleaseNotOwned) + LAZY_INIT_BUGTYPE(DeallocNotOwned) + LAZY_INIT_BUGTYPE(FreeNotOwned) + LAZY_INIT_BUGTYPE(OverAutorelease) + LAZY_INIT_BUGTYPE(ReturnNotOwnedForOwned) + LAZY_INIT_BUGTYPE(LeakWithinFunction) + LAZY_INIT_BUGTYPE(LeakAtReturn) +#undef LAZY_INIT_BUGTYPE } bool ento::shouldRegisterOSObjectRetainCountChecker(const CheckerManager &mgr) { diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h index dd79bbef321c38..223e28c2c5b868 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h @@ -251,20 +251,20 @@ class RetainCountChecker eval::Assume, eval::Call > { - RefCountBug useAfterRelease{this, RefCountBug::UseAfterRelease}; - RefCountBug releaseNotOwned{this, RefCountBug::ReleaseNotOwned}; - RefCountBug deallocNotOwned{this, RefCountBug::DeallocNotOwned}; - RefCountBug freeNotOwned{this, RefCountBug::FreeNotOwned}; - RefCountBug overAutorelease{this, RefCountBug::OverAutorelease}; - RefCountBug returnNotOwnedForOwned{this, RefCountBug::ReturnNotOwnedForOwned}; - RefCountBug leakWithinFunction{this, RefCountBug::LeakWithinFunction}; - RefCountBug leakAtReturn{this, RefCountBug::LeakAtReturn}; - - CheckerProgramPointTag DeallocSentTag{this, "DeallocSent"}; - CheckerProgramPointTag CastFailTag{this, "DynamicCastFail"}; +public: + std::unique_ptr UseAfterRelease; + std::unique_ptr ReleaseNotOwned; + std::unique_ptr DeallocNotOwned; + std::unique_ptr FreeNotOwned; + std::unique_ptr OverAutorelease; + std::unique_ptr ReturnNotOwnedForOwned; + std::unique_ptr LeakWithinFunction; + std::unique_ptr LeakAtReturn; mutable std::unique_ptr Summaries; -public: + + static std::unique_ptr DeallocSentTag; + static std::unique_ptr CastFailTag; /// Track Objective-C and CoreFoundation objects. bool TrackObjCAndCFObjects = false; @@ -360,13 +360,11 @@ class RetainCountChecker CheckerContext &Ctx, ExplodedNode *Pred = nullptr) const; - const CheckerProgramPointTag &getDeallocSentTag() const { - return DeallocSentTag; + static const CheckerProgramPointTag &getDeallocSentTag() { + return *DeallocSentTag; } - const CheckerProgramPointTag &getCastFailTag() const { - return CastFailTag; - } + static const CheckerProgramPointTag &getCastFailTag() { return *CastFailTag; } private: /// Perform the necessary checks and state adjustments at the end of the diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp index cfad47626354ab..1d8ed90f7590c2 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp @@ -18,7 +18,7 @@ using namespace clang; using namespace ento; using namespace retaincountchecker; -StringRef RefCountBug::bugTypeToName(RefCountBug::RefCountBugType BT) { +StringRef RefCountBug::bugTypeToName(RefCountBug::RefCountBugKind BT) { switch (BT) { case UseAfterRelease: return "Use-after-release"; @@ -37,7 +37,7 @@ StringRef RefCountBug::bugTypeToName(RefCountBug::RefCountBugType BT) { case LeakAtReturn: return "Leak of returned object"; } - llvm_unreachable("Unknown RefCountBugType"); + llvm_unreachable("Unknown RefCountBugKind"); } StringRef RefCountBug::getDescription() const { @@ -60,13 +60,14 @@ StringRef RefCountBug::getDescription() const { case LeakAtReturn: return ""; } - llvm_unreachable("Unknown RefCountBugType"); + llvm_unreachable("Unknown RefCountBugKind"); } -RefCountBug::RefCountBug(const CheckerBase *Checker, RefCountBugType BT) +RefCountBug::RefCountBug(CheckerNameRef Checker, RefCountBugKind BT) : BugType(Checker, bugTypeToName(BT), categories::MemoryRefCount, - /*SuppressOnSink=*/BT == LeakWithinFunction || BT == LeakAtReturn), - BT(BT), Checker(Checker) {} + /*SuppressOnSink=*/BT == LeakWithinFunction || + BT == LeakAtReturn), + BT(BT) {} static bool isNumericLiteralExpression(const Expr *E) { // FIXME: This set of cases was copied from SemaExprObjC. @@ -453,8 +454,6 @@ RefCountReportVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC, PathSensitiveBugReport &BR) { const auto &BT = static_cast(BR.getBugType()); - const auto *Checker = - static_cast(BT.getChecker()); bool IsFreeUnowned = BT.getBugType() == RefCountBug::FreeNotOwned || BT.getBugType() == RefCountBug::DeallocNotOwned; @@ -545,11 +544,11 @@ RefCountReportVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC, const ProgramPointTag *Tag = N->getLocation().getTag(); - if (Tag == &Checker->getCastFailTag()) { + if (Tag == &RetainCountChecker::getCastFailTag()) { os << "Assuming dynamic cast returns null due to type mismatch"; } - if (Tag == &Checker->getDeallocSentTag()) { + if (Tag == &RetainCountChecker::getDeallocSentTag()) { // We only have summaries attached to nodes after evaluating CallExpr and // ObjCMessageExprs. const Stmt *S = N->getLocation().castAs().getStmt(); diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h index e9e27775405481..286a8ae2ef7d7b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h +++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h @@ -26,7 +26,7 @@ namespace retaincountchecker { class RefCountBug : public BugType { public: - enum RefCountBugType { + enum RefCountBugKind { UseAfterRelease, ReleaseNotOwned, DeallocNotOwned, @@ -36,21 +36,14 @@ class RefCountBug : public BugType { LeakWithinFunction, LeakAtReturn, }; - RefCountBug(const CheckerBase *checker, RefCountBugType BT); + RefCountBug(CheckerNameRef Checker, RefCountBugKind BT); StringRef getDescription() const; - RefCountBugType getBugType() const { - return BT; - } - - const CheckerBase *getChecker() const { - return Checker; - } + RefCountBugKind getBugType() const { return BT; } private: - RefCountBugType BT; - const CheckerBase *Checker; - static StringRef bugTypeToName(RefCountBugType BT); + RefCountBugKind BT; + static StringRef bugTypeToName(RefCountBugKind BT); }; class RefCountReport : public PathSensitiveBugReport { diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h new file mode 100644 index 00000000000000..26d79cfcd9b519 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h @@ -0,0 +1,70 @@ +//=======- ASTUtis.h ---------------------------------------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYZER_WEBKIT_ASTUTILS_H +#define LLVM_CLANG_ANALYZER_WEBKIT_ASTUTILS_H + +#include "clang/AST/Decl.h" +#include "llvm/ADT/APInt.h" +#include "llvm/Support/Casting.h" + +#include +#include + +namespace clang { +class CXXRecordDecl; +class CXXBaseSpecifier; +class FunctionDecl; +class CXXMethodDecl; +class Expr; + +/// If passed expression is of type uncounted pointer/reference we try to find +/// the origin of this pointer. Example: Origin can be a local variable, nullptr +/// constant or this-pointer. +/// +/// Certain subexpression nodes represent transformations that don't affect +/// where the memory address originates from. We try to traverse such +/// subexpressions to get to the relevant child nodes. Whenever we encounter a +/// subexpression that either can't be ignored, we don't model its semantics or +/// that has multiple children we stop. +/// +/// \p E is an expression of uncounted pointer/reference type. +/// If \p StopAtFirstRefCountedObj is true and we encounter a subexpression that +/// represents ref-counted object during the traversal we return relevant +/// sub-expression and true. +/// +/// \returns subexpression that we traversed to and if \p +/// StopAtFirstRefCountedObj is true we also return whether we stopped early. +std::pair +tryToFindPtrOrigin(const clang::Expr *E, bool StopAtFirstRefCountedObj); + +/// For \p E referring to a ref-countable/-counted pointer/reference we return +/// whether it's a safe call argument. Examples: function parameter or +/// this-pointer. The logic relies on the set of recursive rules we enforce for +/// WebKit codebase. +/// +/// \returns Whether \p E is a safe call arugment. +bool isASafeCallArg(const clang::Expr *E); + +/// \returns name of AST node or empty string. +template std::string safeGetName(const T *ASTNode) { + const auto *const ND = llvm::dyn_cast_or_null(ASTNode); + if (!ND) + return ""; + + // In case F is for example "operator|" the getName() method below would + // assert. + if (!ND->getDeclName().isIdentifier()) + return ""; + + return ND->getName().str(); +} + +} // namespace clang + +#endif diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h new file mode 100644 index 00000000000000..4979b8ffc2b20c --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/DiagOutputUtils.h @@ -0,0 +1,28 @@ +//=======- DiagOutputUtils.h -------------------------------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYZER_WEBKIT_DIAGPRINTUTILS_H +#define LLVM_CLANG_ANALYZER_WEBKIT_DIAGPRINTUTILS_H + +#include "clang/AST/Decl.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { + +template +void printQuotedQualifiedName(llvm::raw_ostream &Os, + const NamedDeclDerivedT &D) { + Os << "'"; + D->getNameForDiagnostic(Os, D->getASTContext().getPrintingPolicy(), + /*Qualified=*/true); + Os << "'"; +} + +} // namespace clang + +#endif diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp new file mode 100644 index 00000000000000..168cfd511170ce --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -0,0 +1,172 @@ +//=======- PtrTypesSemantics.cpp ---------------------------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PtrTypesSemantics.h" +#include "ASTUtils.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" + +using llvm::Optional; +using namespace clang; + +namespace { + +bool hasPublicRefAndDeref(const CXXRecordDecl *R) { + assert(R); + + bool hasRef = false; + bool hasDeref = false; + for (const CXXMethodDecl *MD : R->methods()) { + const auto MethodName = safeGetName(MD); + + if (MethodName == "ref" && MD->getAccess() == AS_public) { + if (hasDeref) + return true; + hasRef = true; + } else if (MethodName == "deref" && MD->getAccess() == AS_public) { + if (hasRef) + return true; + hasDeref = true; + } + } + return false; +} + +} // namespace + +namespace clang { + +const CXXRecordDecl *isRefCountable(const CXXBaseSpecifier *Base) { + assert(Base); + + const Type *T = Base->getType().getTypePtrOrNull(); + if (!T) + return nullptr; + + const CXXRecordDecl *R = T->getAsCXXRecordDecl(); + if (!R) + return nullptr; + + return hasPublicRefAndDeref(R) ? R : nullptr; +} + +bool isRefCountable(const CXXRecordDecl *R) { + assert(R); + + R = R->getDefinition(); + assert(R); + + if (hasPublicRefAndDeref(R)) + return true; + + CXXBasePaths Paths; + Paths.setOrigin(const_cast(R)); + + const auto isRefCountableBase = [](const CXXBaseSpecifier *Base, + CXXBasePath &) { + return clang::isRefCountable(Base); + }; + + return R->lookupInBases(isRefCountableBase, Paths, + /*LookupInDependent =*/true); +} + +bool isCtorOfRefCounted(const clang::FunctionDecl *F) { + assert(F); + const auto &FunctionName = safeGetName(F); + + return FunctionName == "Ref" || FunctionName == "makeRef" + + || FunctionName == "RefPtr" || FunctionName == "makeRefPtr" + + || FunctionName == "UniqueRef" || FunctionName == "makeUniqueRef" || + FunctionName == "makeUniqueRefWithoutFastMallocCheck" + + || FunctionName == "String" || FunctionName == "AtomString" || + FunctionName == "UniqueString" + // FIXME: Implement as attribute. + || FunctionName == "Identifier"; +} + +bool isUncounted(const CXXRecordDecl *Class) { + // Keep isRefCounted first as it's cheaper. + return !isRefCounted(Class) && isRefCountable(Class); +} + +bool isUncountedPtr(const Type *T) { + assert(T); + + if (T->isPointerType() || T->isReferenceType()) { + if (auto *CXXRD = T->getPointeeCXXRecordDecl()) { + return isUncounted(CXXRD); + } + } + return false; +} + +bool isGetterOfRefCounted(const CXXMethodDecl *M) { + assert(M); + + if (isa(M)) { + const CXXRecordDecl *calleeMethodsClass = M->getParent(); + auto className = safeGetName(calleeMethodsClass); + auto methodName = safeGetName(M); + + if (((className == "Ref" || className == "RefPtr") && + methodName == "get") || + ((className == "String" || className == "AtomString" || + className == "AtomStringImpl" || className == "UniqueString" || + className == "UniqueStringImpl" || className == "Identifier") && + methodName == "impl")) + return true; + + // Ref -> T conversion + // FIXME: Currently allowing any Ref -> whatever cast. + if (className == "Ref" || className == "RefPtr") { + if (auto *maybeRefToRawOperator = dyn_cast(M)) { + if (auto *targetConversionType = + maybeRefToRawOperator->getConversionType().getTypePtrOrNull()) { + if (isUncountedPtr(targetConversionType)) { + return true; + } + } + } + } + } + return false; +} + +bool isRefCounted(const CXXRecordDecl *R) { + assert(R); + if (auto *TmplR = R->getTemplateInstantiationPattern()) { + // FIXME: String/AtomString/UniqueString + const auto &ClassName = safeGetName(TmplR); + return ClassName == "RefPtr" || ClassName == "Ref"; + } + return false; +} + +bool isPtrConversion(const FunctionDecl *F) { + assert(F); + if (isCtorOfRefCounted(F)) + return true; + + // FIXME: check # of params == 1 + const auto FunctionName = safeGetName(F); + if (FunctionName == "getPtr" || FunctionName == "WeakPtr" || + FunctionName == "makeWeakPtr" + + || FunctionName == "downcast" || FunctionName == "bitwise_cast") + return true; + + return false; +} + +} // namespace clang diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h new file mode 100644 index 00000000000000..83d9c0bcc13b38 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h @@ -0,0 +1,59 @@ +//=======- PtrTypesSemantics.cpp ---------------------------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYZER_WEBKIT_PTRTYPESEMANTICS_H +#define LLVM_CLANG_ANALYZER_WEBKIT_PTRTYPESEMANTICS_H + +namespace clang { +class CXXBaseSpecifier; +class CXXMethodDecl; +class CXXRecordDecl; +class Expr; +class FunctionDecl; +class Type; + +// Ref-countability of a type is implicitly defined by Ref and RefPtr +// implementation. It can be modeled as: type T having public methods ref() and +// deref() + +// In WebKit there are two ref-counted templated smart pointers: RefPtr and +// Ref. + +/// \returns CXXRecordDecl of the base if the type is ref-countable, nullptr if +/// not. +const clang::CXXRecordDecl *isRefCountable(const clang::CXXBaseSpecifier *Base); + +/// \returns true if \p Class is ref-countable, false if not. +/// Asserts that \p Class IS a definition. +bool isRefCountable(const clang::CXXRecordDecl *Class); + +/// \returns true if \p Class is ref-counted, false if not. +bool isRefCounted(const clang::CXXRecordDecl *Class); + +/// \returns true if \p Class is ref-countable AND not ref-counted, false if +/// not. Asserts that \p Class IS a definition. +bool isUncounted(const clang::CXXRecordDecl *Class); + +/// \returns true if \p T is either a raw pointer or reference to an uncounted +/// class, false if not. +bool isUncountedPtr(const clang::Type *T); + +/// \returns true if \p F creates ref-countable object from uncounted parameter, +/// false if not. +bool isCtorOfRefCounted(const clang::FunctionDecl *F); + +/// \returns true if \p M is getter of a ref-counted class, false if not. +bool isGetterOfRefCounted(const clang::CXXMethodDecl *Method); + +/// \returns true if \p F is a conversion between ref-countable or ref-counted +/// pointer types. +bool isPtrConversion(const FunctionDecl *F); + +} // namespace clang + +#endif diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp new file mode 100644 index 00000000000000..81ce284c2dc7c5 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp @@ -0,0 +1,167 @@ +//=======- RefCntblBaseVirtualDtor.cpp ---------------------------*- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "DiagOutputUtils.h" +#include "PtrTypesSemantics.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" + +using namespace clang; +using namespace ento; + +namespace { +class RefCntblBaseVirtualDtorChecker + : public Checker> { +private: + BugType Bug; + mutable BugReporter *BR; + +public: + RefCntblBaseVirtualDtorChecker() + : Bug(this, + "Reference-countable base class doesn't have virtual destructor", + "WebKit coding guidelines") {} + + void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR, + BugReporter &BRArg) const { + BR = &BRArg; + + // The calls to checkAST* from AnalysisConsumer don't + // visit template instantiations or lambda classes. We + // want to visit those, so we make our own RecursiveASTVisitor. + struct LocalVisitor : public RecursiveASTVisitor { + const RefCntblBaseVirtualDtorChecker *Checker; + explicit LocalVisitor(const RefCntblBaseVirtualDtorChecker *Checker) + : Checker(Checker) { + assert(Checker); + } + + bool shouldVisitTemplateInstantiations() const { return true; } + bool shouldVisitImplicitCode() const { return false; } + + bool VisitCXXRecordDecl(const CXXRecordDecl *RD) { + Checker->visitCXXRecordDecl(RD); + return true; + } + }; + + LocalVisitor visitor(this); + visitor.TraverseDecl(const_cast(TUD)); + } + + void visitCXXRecordDecl(const CXXRecordDecl *RD) const { + if (shouldSkipDecl(RD)) + return; + + CXXBasePaths Paths; + Paths.setOrigin(RD); + + const CXXBaseSpecifier *ProblematicBaseSpecifier = nullptr; + const CXXRecordDecl *ProblematicBaseClass = nullptr; + + const auto IsPublicBaseRefCntblWOVirtualDtor = + [RD, &ProblematicBaseSpecifier, + &ProblematicBaseClass](const CXXBaseSpecifier *Base, CXXBasePath &) { + const auto AccSpec = Base->getAccessSpecifier(); + if (AccSpec == AS_protected || AccSpec == AS_private || + (AccSpec == AS_none && RD->isClass())) + return false; + + llvm::Optional MaybeRefCntblBaseRD = + isRefCountable(Base); + if (!MaybeRefCntblBaseRD.hasValue()) + return false; + + const CXXRecordDecl *RefCntblBaseRD = MaybeRefCntblBaseRD.getValue(); + if (!RefCntblBaseRD) + return false; + + const auto *Dtor = RefCntblBaseRD->getDestructor(); + if (!Dtor || !Dtor->isVirtual()) { + ProblematicBaseSpecifier = Base; + ProblematicBaseClass = RefCntblBaseRD; + return true; + } + + return false; + }; + + if (RD->lookupInBases(IsPublicBaseRefCntblWOVirtualDtor, Paths, + /*LookupInDependent =*/true)) { + reportBug(RD, ProblematicBaseSpecifier, ProblematicBaseClass); + } + } + + bool shouldSkipDecl(const CXXRecordDecl *RD) const { + if (!RD->isThisDeclarationADefinition()) + return true; + + if (RD->isImplicit()) + return true; + + if (RD->isLambda()) + return true; + + // If the construct doesn't have a source file, then it's not something + // we want to diagnose. + const auto RDLocation = RD->getLocation(); + if (!RDLocation.isValid()) + return true; + + const auto Kind = RD->getTagKind(); + if (Kind != TTK_Struct && Kind != TTK_Class) + return true; + + // Ignore CXXRecords that come from system headers. + if (BR->getSourceManager().getFileCharacteristic(RDLocation) != + SrcMgr::C_User) + return true; + + return false; + } + + void reportBug(const CXXRecordDecl *DerivedClass, + const CXXBaseSpecifier *BaseSpec, + const CXXRecordDecl *ProblematicBaseClass) const { + assert(DerivedClass); + assert(BaseSpec); + assert(ProblematicBaseClass); + + SmallString<100> Buf; + llvm::raw_svector_ostream Os(Buf); + + Os << (ProblematicBaseClass->isClass() ? "Class" : "Struct") << " "; + printQuotedQualifiedName(Os, ProblematicBaseClass); + + Os << " is used as a base of " + << (DerivedClass->isClass() ? "class" : "struct") << " "; + printQuotedQualifiedName(Os, DerivedClass); + + Os << " but doesn't have virtual destructor"; + + PathDiagnosticLocation BSLoc(BaseSpec->getSourceRange().getBegin(), + BR->getSourceManager()); + auto Report = std::make_unique(Bug, Os.str(), BSLoc); + Report->addRange(BaseSpec->getSourceRange()); + BR->emitReport(std::move(Report)); + } +}; +} // namespace + +void ento::registerRefCntblBaseVirtualDtorChecker(CheckerManager &Mgr) { + Mgr.registerChecker(); +} + +bool ento::shouldRegisterRefCntblBaseVirtualDtorChecker( + const CheckerManager &mgr) { + return true; +} diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 3b2e5cd28e437b..ad79f7cb9359fc 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -45,7 +45,6 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" diff --git a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt index 057cdd4bb18aba..233ffaf7995685 100644 --- a/clang/lib/StaticAnalyzer/Core/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Core/CMakeLists.txt @@ -44,7 +44,6 @@ add_clang_library(clangStaticAnalyzerCore SimpleSValBuilder.cpp SMTConstraintManager.cpp Store.cpp - SubEngine.cpp SValBuilder.cpp SVals.cpp SymbolManager.cpp diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index 1ea7c26dc76b02..fb728ac9e4f5a1 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -564,7 +564,7 @@ RuntimeDefinition AnyFunctionCall::getRuntimeDefinition() const { return RuntimeDefinition(Decl); } - SubEngine &Engine = getState()->getStateManager().getOwningEngine(); + ExprEngine &Engine = getState()->getStateManager().getOwningEngine(); AnalyzerOptions &Opts = Engine.getAnalysisManager().options; // Try to get CTU definition only if CTUDir is provided. diff --git a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp index 5a49b18aecf12e..70deb13a8e1ae9 100644 --- a/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -23,8 +23,8 @@ #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/StaticAnalyzer/Core/PathSensitive/BlockCounter.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/FunctionSummary.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/WorkList.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" @@ -52,8 +52,7 @@ STATISTIC(NumPathsExplored, // Core analysis engine. //===----------------------------------------------------------------------===// -static std::unique_ptr generateWorkList(AnalyzerOptions &Opts, - SubEngine &subengine) { +static std::unique_ptr generateWorkList(AnalyzerOptions &Opts) { switch (Opts.getExplorationStrategy()) { case ExplorationStrategyKind::DFS: return WorkList::makeDFS(); @@ -71,9 +70,9 @@ static std::unique_ptr generateWorkList(AnalyzerOptions &Opts, llvm_unreachable("Unknown AnalyzerOptions::ExplorationStrategyKind"); } -CoreEngine::CoreEngine(SubEngine &subengine, FunctionSummariesTy *FS, +CoreEngine::CoreEngine(ExprEngine &exprengine, FunctionSummariesTy *FS, AnalyzerOptions &Opts) - : SubEng(subengine), WList(generateWorkList(Opts, subengine)), + : ExprEng(exprengine), WList(generateWorkList(Opts)), BCounterFactory(G.getAllocator()), FunctionSummaries(FS) {} /// ExecuteWorkList - Run the worklist algorithm for a maximum number of steps. @@ -104,7 +103,7 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, WList->setBlockCounter(BCounterFactory.GetEmptyCounter()); if (!InitState) - InitState = SubEng.getInitialState(L); + InitState = ExprEng.getInitialState(L); bool IsNew; ExplodedNode *Node = G.getNode(StartLoc, InitState, false, &IsNew); @@ -113,7 +112,7 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, NodeBuilderContext BuilderCtx(*this, StartLoc.getDst(), Node); ExplodedNodeSet DstBegin; - SubEng.processBeginOfFunction(BuilderCtx, Node, DstBegin, StartLoc); + ExprEng.processBeginOfFunction(BuilderCtx, Node, DstBegin, StartLoc); enqueue(DstBegin); } @@ -147,7 +146,7 @@ bool CoreEngine::ExecuteWorkList(const LocationContext *L, unsigned Steps, dispatchWorkItem(Node, Node->getLocation(), WU); } - SubEng.processEndWorklist(); + ExprEng.processEndWorklist(); return WList->hasWork(); } @@ -172,7 +171,7 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc, break; case ProgramPoint::CallExitBeginKind: - SubEng.processCallExit(Pred); + ExprEng.processCallExit(Pred); break; case ProgramPoint::EpsilonKind: { @@ -253,17 +252,17 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) { } // Process the final state transition. - SubEng.processEndOfFunction(BuilderCtx, Pred, RS); + ExprEng.processEndOfFunction(BuilderCtx, Pred, RS); // This path is done. Don't enqueue any more nodes. return; } - // Call into the SubEngine to process entering the CFGBlock. + // Call into the ExprEngine to process entering the CFGBlock. ExplodedNodeSet dstNodes; BlockEntrance BE(Blk, Pred->getLocationContext()); NodeBuilderWithSinks nodeBuilder(Pred, dstNodes, BuilderCtx, BE); - SubEng.processCFGBlockEntrance(L, nodeBuilder, Pred); + ExprEng.processCFGBlockEntrance(L, nodeBuilder, Pred); // Auto-generate a node. if (!nodeBuilder.hasGeneratedNodes()) { @@ -287,7 +286,7 @@ void CoreEngine::HandleBlockEntrance(const BlockEntrance &L, // Process the entrance of the block. if (Optional E = L.getFirstElement()) { NodeBuilderContext Ctx(*this, L.getBlock(), Pred); - SubEng.processCFGElement(*E, Pred, 0, &Ctx); + ExprEng.processCFGElement(*E, Pred, 0, &Ctx); } else HandleBlockExit(L.getBlock(), Pred); @@ -367,7 +366,7 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) { builder(Pred, B, cast(Term)->getTarget(), *(B->succ_begin()), this); - SubEng.processIndirectGoto(builder); + ExprEng.processIndirectGoto(builder); return; } @@ -378,7 +377,7 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) { // 'element' variable to a value. // (2) in a terminator, which represents the branch. // - // For (1), subengines will bind a value (i.e., 0 or 1) indicating + // For (1), ExprEngine will bind a value (i.e., 0 or 1) indicating // whether or not collection contains any more elements. We cannot // just test to see if the element is nil because a container can // contain nil elements. @@ -389,7 +388,7 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) { SwitchNodeBuilder builder(Pred, B, cast(Term)->getCond(), this); - SubEng.processSwitch(builder); + ExprEng.processSwitch(builder); return; } @@ -418,7 +417,7 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) { void CoreEngine::HandleCallEnter(const CallEnter &CE, ExplodedNode *Pred) { NodeBuilderContext BuilderCtx(*this, CE.getEntry(), Pred); - SubEng.processCallEnter(BuilderCtx, CE, Pred); + ExprEng.processCallEnter(BuilderCtx, CE, Pred); } void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term, @@ -426,7 +425,7 @@ void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term, assert(B->succ_size() == 2); NodeBuilderContext Ctx(*this, B, Pred); ExplodedNodeSet Dst; - SubEng.processBranch(Cond, Ctx, Pred, Dst, *(B->succ_begin()), + ExprEng.processBranch(Cond, Ctx, Pred, Dst, *(B->succ_begin()), *(B->succ_begin() + 1)); // Enqueue the new frontier onto the worklist. enqueue(Dst); @@ -438,7 +437,7 @@ void CoreEngine::HandleCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE, assert(B->succ_size() == 2); NodeBuilderContext Ctx(*this, B, Pred); ExplodedNodeSet Dst; - SubEng.processCleanupTemporaryBranch(BTE, Ctx, Pred, Dst, *(B->succ_begin()), + ExprEng.processCleanupTemporaryBranch(BTE, Ctx, Pred, Dst, *(B->succ_begin()), *(B->succ_begin() + 1)); // Enqueue the new frontier onto the worklist. enqueue(Dst); @@ -449,7 +448,7 @@ void CoreEngine::HandleStaticInit(const DeclStmt *DS, const CFGBlock *B, assert(B->succ_size() == 2); NodeBuilderContext Ctx(*this, B, Pred); ExplodedNodeSet Dst; - SubEng.processStaticInitializer(DS, Ctx, Pred, Dst, + ExprEng.processStaticInitializer(DS, Ctx, Pred, Dst, *(B->succ_begin()), *(B->succ_begin()+1)); // Enqueue the new frontier onto the worklist. enqueue(Dst); @@ -464,7 +463,7 @@ void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, HandleBlockExit(B, Pred); else { NodeBuilderContext Ctx(*this, B, Pred); - SubEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx, &Ctx); + ExprEng.processCFGElement((*B)[StmtIdx], Pred, StmtIdx, &Ctx); } } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 36b930faf2d026..6fce27bc95569c 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -3206,3 +3206,5 @@ void *ProgramStateTrait::GDMIndex() { static int index = 0; return &index; } + +void ExprEngine::anchor() { } diff --git a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index 8ce3aa2e081ed4..bc7c41d039c4d0 100644 --- a/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -21,7 +21,6 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/Token.h" -#include "clang/Driver/DriverDiagnostic.h" #include "clang/Rewrite/Core/HTMLRewrite.h" #include "clang/Rewrite/Core/Rewriter.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" @@ -138,14 +137,18 @@ void ento::createHTMLDiagnosticConsumer( const std::string &OutputDir, const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &CTU) { - if (OutputDir.empty()) { - PP.getDiagnostics().Report(diag::err_analyzer_missing_output_loc) - << "html" << "directory"; + // FIXME: HTML is currently our default output type, but if the output + // directory isn't specified, it acts like if it was in the minimal text + // output mode. This doesn't make much sense, we should have the minimal text + // as our default. In the case of backward compatibility concerns, this could + // be preserved with -analyzer-config-compatibility-mode=true. + createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, OutputDir, PP, CTU); + + // TODO: Emit an error here. + if (OutputDir.empty()) return; - } C.push_back(new HTMLDiagnostics(AnalyzerOpts, OutputDir, PP, true)); - createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, OutputDir, PP, CTU); } void ento::createHTMLSingleFileDiagnosticConsumer( @@ -153,11 +156,9 @@ void ento::createHTMLSingleFileDiagnosticConsumer( const std::string &OutputDir, const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &CTU) { - if (OutputDir.empty()) { - PP.getDiagnostics().Report(diag::err_analyzer_missing_output_loc) - << "html-single-file" << "directory"; + // TODO: Emit an error here. + if (OutputDir.empty()) return; - } C.push_back(new HTMLDiagnostics(AnalyzerOpts, OutputDir, PP, false)); createTextMinimalPathDiagnosticConsumer(AnalyzerOpts, C, OutputDir, PP, CTU); @@ -167,13 +168,6 @@ void ento::createPlistHTMLDiagnosticConsumer( AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, const std::string &prefix, const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &CTU) { - - if (prefix.empty()) { - PP.getDiagnostics().Report(diag::err_analyzer_missing_output_loc) - << "plist-html" << "directory"; - return; - } - createHTMLDiagnosticConsumer( AnalyzerOpts, C, std::string(llvm::sys::path::parent_path(prefix)), PP, CTU); @@ -1076,8 +1070,13 @@ StringRef HTMLDiagnostics::generateKeyboardNavigationJavascript() {