diff options
Diffstat (limited to 'clang-tools-extra/clang-tidy')
16 files changed, 440 insertions, 29 deletions
diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp index ed1fd13..824ebdf 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -38,6 +38,7 @@ #include "IncorrectRoundingsCheck.h" #include "InfiniteLoopCheck.h" #include "IntegerDivisionCheck.h" +#include "InvalidEnumDefaultInitializationCheck.h" #include "LambdaFunctionNameCheck.h" #include "MacroParenthesesCheck.h" #include "MacroRepeatedSideEffectsCheck.h" @@ -165,6 +166,8 @@ public: CheckFactories.registerCheck<InfiniteLoopCheck>("bugprone-infinite-loop"); CheckFactories.registerCheck<IntegerDivisionCheck>( "bugprone-integer-division"); + CheckFactories.registerCheck<InvalidEnumDefaultInitializationCheck>( + "bugprone-invalid-enum-default-initialization"); CheckFactories.registerCheck<LambdaFunctionNameCheck>( "bugprone-lambda-function-name"); CheckFactories.registerCheck<MacroParenthesesCheck>( diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt index d862794..59928e5 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -30,6 +30,7 @@ add_clang_library(clangTidyBugproneModule STATIC InaccurateEraseCheck.cpp IncorrectEnableIfCheck.cpp IncorrectEnableSharedFromThisCheck.cpp + InvalidEnumDefaultInitializationCheck.cpp UnintendedCharOstreamOutputCheck.cpp ReturnConstRefFromParameterCheck.cpp SuspiciousStringviewDataUsageCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp new file mode 100644 index 0000000..33fcf45 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp @@ -0,0 +1,180 @@ +//===--- InvalidEnumDefaultInitializationCheck.cpp - clang-tidy -----------===// +// +// 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 "InvalidEnumDefaultInitializationCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/TypeVisitor.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include <algorithm> + +using namespace clang::ast_matchers; + +namespace clang::tidy::bugprone { + +namespace { + +bool isCompleteAndHasNoZeroValue(const EnumDecl *D) { + const EnumDecl *Definition = D->getDefinition(); + return Definition && Definition->isComplete() && + !Definition->enumerators().empty() && + std::none_of(Definition->enumerator_begin(), + Definition->enumerator_end(), + [](const EnumConstantDecl *Value) { + return Value->getInitVal().isZero(); + }); +} + +AST_MATCHER(EnumDecl, isCompleteAndHasNoZeroValue) { + return isCompleteAndHasNoZeroValue(&Node); +} + +// Find an initialization which initializes the value (if it has enum type) to a +// default zero value. +AST_MATCHER(Expr, isEmptyInit) { + if (isa<CXXScalarValueInitExpr, ImplicitValueInitExpr>(&Node)) + return true; + if (const auto *Init = dyn_cast<InitListExpr>(&Node)) { + if (Init->getNumInits() == 0) + return true; + } + return false; +} + +AST_MATCHER(InitListExpr, hasArrayFiller) { return Node.hasArrayFiller(); } + +// Check if any type has a "child" type that is an enum without zero value. +// The "child" type can be an array element type or member type of a record +// type (or a recursive combination of these). In this case, if the "root" type +// is statically initialized, the enum component is initialized to zero. +class FindEnumMember : public TypeVisitor<FindEnumMember, bool> { +public: + const EnumType *FoundEnum = nullptr; + + bool VisitType(const Type *T) { + const Type *DesT = T->getUnqualifiedDesugaredType(); + if (DesT != T) + return Visit(DesT); + return false; + } + bool VisitArrayType(const ArrayType *T) { + return Visit(T->getElementType().getTypePtr()); + } + bool VisitConstantArrayType(const ConstantArrayType *T) { + return Visit(T->getElementType().getTypePtr()); + } + bool VisitEnumType(const EnumType *T) { + if (isCompleteAndHasNoZeroValue(T->getDecl())) { + FoundEnum = T; + return true; + } + return false; + } + bool VisitRecordType(const RecordType *T) { + const RecordDecl *RD = T->getDecl(); + if (RD->isUnion()) + return false; + auto VisitField = [this](const FieldDecl *F) { + return Visit(F->getType().getTypePtr()); + }; + return llvm::any_of(RD->fields(), VisitField); + } +}; + +} // namespace + +InvalidEnumDefaultInitializationCheck::InvalidEnumDefaultInitializationCheck( + StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + +void InvalidEnumDefaultInitializationCheck::registerMatchers( + MatchFinder *Finder) { + auto EnumWithoutZeroValue = enumType( + hasDeclaration(enumDecl(isCompleteAndHasNoZeroValue()).bind("enum"))); + auto EnumOrArrayOfEnum = qualType(hasUnqualifiedDesugaredType( + anyOf(EnumWithoutZeroValue, + arrayType(hasElementType(qualType( + hasUnqualifiedDesugaredType(EnumWithoutZeroValue))))))); + Finder->addMatcher( + expr(isEmptyInit(), hasType(EnumOrArrayOfEnum)).bind("expr"), this); + + // Array initialization can contain an "array filler" for the (syntactically) + // unspecified elements. This expression is not found by AST matchers and can + // have any type (the array's element type). This is an implicitly generated + // initialization, so if the type contains somewhere an enum without zero + // enumerator, the zero initialization applies here. We search this array + // element type for the specific enum type manually when this matcher matches. + Finder->addMatcher(initListExpr(hasArrayFiller()).bind("array_filler_expr"), + this); +} + +void InvalidEnumDefaultInitializationCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *InitExpr = Result.Nodes.getNodeAs<Expr>("expr"); + const auto *Enum = Result.Nodes.getNodeAs<EnumDecl>("enum"); + if (!InitExpr) { + const auto *InitList = + Result.Nodes.getNodeAs<InitListExpr>("array_filler_expr"); + // Initialization of omitted array elements with array filler was found. + // Check the type for enum without zero value. + // FIXME: In this way only one enum-typed value is found, not all of these. + FindEnumMember Finder; + if (!Finder.Visit(InitList->getArrayFiller()->getType().getTypePtr())) + return; + InitExpr = InitList; + Enum = Finder.FoundEnum->getDecl(); + } + + if (!InitExpr || !Enum) + return; + + ASTContext &ACtx = Enum->getASTContext(); + SourceLocation Loc = InitExpr->getExprLoc(); + if (Loc.isInvalid()) { + if (isa<ImplicitValueInitExpr, InitListExpr>(InitExpr)) { + DynTypedNodeList Parents = ACtx.getParents(*InitExpr); + if (Parents.empty()) + return; + + if (const auto *Ctor = Parents[0].get<CXXConstructorDecl>()) { + // Try to find member initializer with the found expression and get the + // source location from it. + CXXCtorInitializer *const *CtorInit = std::find_if( + Ctor->init_begin(), Ctor->init_end(), + [InitExpr](const CXXCtorInitializer *Init) { + return Init->isMemberInitializer() && Init->getInit() == InitExpr; + }); + if (!CtorInit) + return; + Loc = (*CtorInit)->getLParenLoc(); + } else if (const auto *InitList = Parents[0].get<InitListExpr>()) { + // The expression may be implicitly generated for an initialization. + // Search for a parent initialization list with valid source location. + while (InitList->getExprLoc().isInvalid()) { + DynTypedNodeList Parents = ACtx.getParents(*InitList); + if (Parents.empty()) + return; + InitList = Parents[0].get<InitListExpr>(); + if (!InitList) + return; + } + Loc = InitList->getExprLoc(); + } + } + // If still not found a source location, omit the warning. + // Ideally all such cases (if they exist) should be handled to make the + // check more precise. + if (Loc.isInvalid()) + return; + } + diag(Loc, "enum value of type %0 initialized with invalid value of 0, " + "enum doesn't have a zero-value enumerator") + << Enum; + diag(Enum->getLocation(), "enum is defined here", DiagnosticIDs::Note); +} + +} // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.h b/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.h new file mode 100644 index 0000000..0746c4d --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.h @@ -0,0 +1,31 @@ +//===--- InvalidEnumDefaultInitializationCheck.h - clang-tidy -*- 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_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INVALIDENUMDEFAULTINITIALIZATIONCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INVALIDENUMDEFAULTINITIALIZATIONCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::bugprone { + +/// Detects default initialization (to 0) of variables with `enum` type where +/// the enum has no enumerator with value of 0. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/invalid-enum-default-initialization.html +class InvalidEnumDefaultInitializationCheck : public ClangTidyCheck { +public: + InvalidEnumDefaultInitializationCheck(StringRef Name, + ClangTidyContext *Context); + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace clang::tidy::bugprone + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_INVALIDENUMDEFAULTINITIALIZATIONCHECK_H diff --git a/clang-tools-extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp index ea3b8b8..dfd3cbf 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp @@ -74,17 +74,25 @@ void SignedCharMisuseCheck::registerMatchers(MatchFinder *Finder) { charCastExpression(true, IntegerType, "signedCastExpression"); const auto UnSignedCharCastExpr = charCastExpression(false, IntegerType, "unsignedCastExpression"); + const bool IsC23 = getLangOpts().C23; - // Catch assignments with signed char -> integer conversion. + // Catch assignments with signed char -> integer conversion. Ignore false + // positives on C23 enums with the fixed underlying type of signed char. const auto AssignmentOperatorExpr = expr(binaryOperator(hasOperatorName("="), hasLHS(hasType(IntegerType)), - hasRHS(SignedCharCastExpr))); + hasRHS(SignedCharCastExpr)), + IsC23 ? unless(binaryOperator( + hasLHS(hasType(hasCanonicalType(enumType()))))) + : Matcher<Stmt>(anything())); Finder->addMatcher(AssignmentOperatorExpr, this); - // Catch declarations with signed char -> integer conversion. - const auto Declaration = varDecl(isDefinition(), hasType(IntegerType), - hasInitializer(SignedCharCastExpr)); + // Catch declarations with signed char -> integer conversion. Ignore false + // positives on C23 enums with the fixed underlying type of signed char. + const auto Declaration = varDecl( + isDefinition(), hasType(IntegerType), hasInitializer(SignedCharCastExpr), + IsC23 ? unless(hasType(hasCanonicalType(enumType()))) + : Matcher<VarDecl>(anything())); Finder->addMatcher(Declaration, this); diff --git a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt index 3232f6e..41386cd 100644 --- a/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/llvm/CMakeLists.txt @@ -11,6 +11,7 @@ add_clang_library(clangTidyLLVMModule STATIC PreferRegisterOverUnsignedCheck.cpp PreferStaticOverAnonymousNamespaceCheck.cpp TwineLocalCheck.cpp + UseNewMLIROpBuilderCheck.cpp LINK_LIBS clangTidy @@ -29,4 +30,5 @@ clang_target_link_libraries(clangTidyLLVMModule clangBasic clangLex clangTooling + clangTransformer ) diff --git a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp b/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp index 0754530..c7c61fd 100644 --- a/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp @@ -18,6 +18,7 @@ #include "PreferRegisterOverUnsignedCheck.h" #include "PreferStaticOverAnonymousNamespaceCheck.h" #include "TwineLocalCheck.h" +#include "UseNewMLIROpBuilderCheck.h" namespace clang::tidy { namespace llvm_check { @@ -40,6 +41,8 @@ public: CheckFactories.registerCheck<readability::QualifiedAutoCheck>( "llvm-qualified-auto"); CheckFactories.registerCheck<TwineLocalCheck>("llvm-twine-local"); + CheckFactories.registerCheck<UseNewMlirOpBuilderCheck>( + "llvm-use-new-mlir-op-builder"); } ClangTidyOptions getModuleOptions() override { diff --git a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp new file mode 100644 index 0000000..4722199 --- /dev/null +++ b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp @@ -0,0 +1,139 @@ +//===--- UseNewMLIROpBuilderCheck.cpp - clang-tidy ------------------------===// +// +// 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 "UseNewMLIROpBuilderCheck.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/LLVM.h" +#include "clang/Lex/Lexer.h" +#include "clang/Tooling/Transformer/RangeSelector.h" +#include "clang/Tooling/Transformer/RewriteRule.h" +#include "clang/Tooling/Transformer/SourceCode.h" +#include "clang/Tooling/Transformer/Stencil.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FormatVariadic.h" + +namespace clang::tidy::llvm_check { +namespace { + +using namespace ::clang::ast_matchers; +using namespace ::clang::transformer; + +EditGenerator rewrite(RangeSelector Call, RangeSelector Builder, + RangeSelector CallArgs) { + // This is using an EditGenerator rather than ASTEdit as we want to warn even + // if in macro. + return [Call = std::move(Call), Builder = std::move(Builder), + CallArgs = + std::move(CallArgs)](const MatchFinder::MatchResult &Result) + -> Expected<SmallVector<transformer::Edit, 1>> { + Expected<CharSourceRange> CallRange = Call(Result); + if (!CallRange) + return CallRange.takeError(); + SourceManager &SM = *Result.SourceManager; + const LangOptions &LangOpts = Result.Context->getLangOpts(); + SourceLocation Begin = CallRange->getBegin(); + + // This will result in just a warning and no edit. + bool InMacro = CallRange->getBegin().isMacroID(); + if (InMacro) { + while (SM.isMacroArgExpansion(Begin)) + Begin = SM.getImmediateExpansionRange(Begin).getBegin(); + Edit WarnOnly; + WarnOnly.Kind = EditKind::Range; + WarnOnly.Range = CharSourceRange::getCharRange(Begin, Begin); + return SmallVector<Edit, 1>({WarnOnly}); + } + + // This will try to extract the template argument as written so that the + // rewritten code looks closest to original. + auto NextToken = [&](std::optional<Token> CurrentToken) { + if (!CurrentToken) + return CurrentToken; + if (CurrentToken->getEndLoc() >= CallRange->getEnd()) + return std::optional<Token>(); + return clang::Lexer::findNextToken(CurrentToken->getLocation(), SM, + LangOpts); + }; + std::optional<Token> LessToken = + clang::Lexer::findNextToken(Begin, SM, LangOpts); + while (LessToken && LessToken->getKind() != clang::tok::less) { + LessToken = NextToken(LessToken); + } + if (!LessToken) { + return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument, + "missing '<' token"); + } + std::optional<Token> EndToken = NextToken(LessToken); + for (std::optional<Token> GreaterToken = NextToken(EndToken); + GreaterToken && GreaterToken->getKind() != clang::tok::greater; + GreaterToken = NextToken(GreaterToken)) { + EndToken = GreaterToken; + } + if (!EndToken) { + return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument, + "missing '>' token"); + } + + Expected<CharSourceRange> BuilderRange = Builder(Result); + if (!BuilderRange) + return BuilderRange.takeError(); + Expected<CharSourceRange> CallArgsRange = CallArgs(Result); + if (!CallArgsRange) + return CallArgsRange.takeError(); + + // Helper for concatting below. + auto GetText = [&](const CharSourceRange &Range) { + return clang::Lexer::getSourceText(Range, SM, LangOpts); + }; + + Edit Replace; + Replace.Kind = EditKind::Range; + Replace.Range = *CallRange; + std::string CallArgsStr; + // Only emit args if there are any. + if (auto CallArgsText = GetText(*CallArgsRange).ltrim(); + !CallArgsText.rtrim().empty()) { + CallArgsStr = llvm::formatv(", {}", CallArgsText); + } + Replace.Replacement = + llvm::formatv("{}::create({}{})", + GetText(CharSourceRange::getTokenRange( + LessToken->getEndLoc(), EndToken->getLastLoc())), + GetText(*BuilderRange), CallArgsStr); + + return SmallVector<Edit, 1>({Replace}); + }; +} + +RewriteRuleWith<std::string> useNewMlirOpBuilderCheckRule() { + Stencil message = cat("use 'OpType::create(builder, ...)' instead of " + "'builder.create<OpType>(...)'"); + // Match a create call on an OpBuilder. + ast_matchers::internal::Matcher<Stmt> base = + cxxMemberCallExpr( + on(expr(hasType( + cxxRecordDecl(isSameOrDerivedFrom("::mlir::OpBuilder")))) + .bind("builder")), + callee(cxxMethodDecl(hasTemplateArgument(0, templateArgument()))), + callee(cxxMethodDecl(hasName("create")))) + .bind("call"); + return applyFirst( + // Attempt rewrite given an lvalue builder, else just warn. + {makeRule(cxxMemberCallExpr(unless(on(cxxTemporaryObjectExpr())), base), + rewrite(node("call"), node("builder"), callArgs("call")), + message), + makeRule(base, noopEdit(node("call")), message)}); +} +} // namespace + +UseNewMlirOpBuilderCheck::UseNewMlirOpBuilderCheck(StringRef Name, + ClangTidyContext *Context) + : TransformerClangTidyCheck(useNewMlirOpBuilderCheckRule(), Name, Context) { +} + +} // namespace clang::tidy::llvm_check diff --git a/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.h b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.h new file mode 100644 index 0000000..813a23c --- /dev/null +++ b/clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.h @@ -0,0 +1,29 @@ +//===--- UseNewMLIROpBuilderCheck.h - clang-tidy ----------------*- 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_TOOLS_EXTRA_CLANG_TIDY_LLVM_USENEWMLIROPBUILDERCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_USENEWMLIROPBUILDERCHECK_H + +#include "../utils/TransformerClangTidyCheck.h" + +namespace clang::tidy::llvm_check { + +/// Checks for uses of MLIR's old/to be deprecated `OpBuilder::create<T>` form +/// and suggests using `T::create` instead. +class UseNewMlirOpBuilderCheck : public utils::TransformerClangTidyCheck { +public: + UseNewMlirOpBuilderCheck(StringRef Name, ClangTidyContext *Context); + + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return getLangOpts().CPlusPlus; + } +}; + +} // namespace clang::tidy::llvm_check + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVM_USENEWMLIROPBUILDERCHECK_H diff --git a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp index 7ea9676..bb8fb240 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp @@ -121,10 +121,11 @@ void UseDesignatedInitializersCheck::registerMatchers(MatchFinder *Finder) { hasAnyBase(hasType(cxxRecordDecl(has(fieldDecl())))); Finder->addMatcher( initListExpr( - hasType(cxxRecordDecl( - RestrictToPODTypes ? isPOD() : isAggregate(), - unless(anyOf(HasBaseWithFields, hasName("::std::array")))) - .bind("type")), + hasType(hasUnqualifiedDesugaredType(recordType(hasDeclaration( + cxxRecordDecl( + RestrictToPODTypes ? isPOD() : isAggregate(), + unless(anyOf(HasBaseWithFields, hasName("::std::array")))) + .bind("type"))))), IgnoreSingleElementAggregates ? hasMoreThanOneElement() : anything(), unless(isFullyDesignated())) .bind("init"), @@ -155,7 +156,7 @@ void UseDesignatedInitializersCheck::check( DiagnosticBuilder Diag = diag(InitList->getLBraceLoc(), "use designated initializer list to initialize %0"); - Diag << Type << InitList->getSourceRange(); + Diag << InitList->getType() << InitList->getSourceRange(); for (const Stmt *InitExpr : *SyntacticInitList) { const auto Designator = Designators[InitExpr->getBeginLoc()]; if (Designator && !Designator->empty()) diff --git a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp index 936a906..e307339 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp @@ -92,7 +92,7 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { const LangOptions &LO = getLangOpts(); // Match CXXRecordDecl only to store the range of the last non-implicit full - // declaration, to later check whether it's within the typdef itself. + // declaration, to later check whether it's within the typedef itself. const auto *MatchedTagDecl = Result.Nodes.getNodeAs<TagDecl>(TagDeclName); if (MatchedTagDecl) { // It is not sufficient to just track the last TagDecl that we've seen, @@ -152,7 +152,7 @@ void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { StringRef ExtraReference = ""; if (MainTypeEndLoc.isValid() && TypeRange.fullyContains(MainTypeEndLoc)) { // Each type introduced in a typedef can specify being a reference or - // pointer type seperately, so we need to sigure out if the new using-decl + // pointer type separately, so we need to figure out if the new using-decl // needs to be to a reference or pointer as well. const SourceLocation Tok = utils::lexer::findPreviousAnyTokenKind( MatchedDecl->getLocation(), SM, LO, tok::TokenKind::star, diff --git a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp index 91a08b9..561f067 100644 --- a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp @@ -106,12 +106,14 @@ QualifiedAutoCheck::QualifiedAutoCheck(StringRef Name, : ClangTidyCheck(Name, Context), AddConstToQualified(Options.get("AddConstToQualified", true)), AllowedTypes( - utils::options::parseStringList(Options.get("AllowedTypes", ""))) {} + utils::options::parseStringList(Options.get("AllowedTypes", ""))), + IgnoreAliasing(Options.get("IgnoreAliasing", true)) {} void QualifiedAutoCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "AddConstToQualified", AddConstToQualified); Options.store(Opts, "AllowedTypes", utils::options::serializeStringList(AllowedTypes)); + Options.store(Opts, "IgnoreAliasing", IgnoreAliasing); } void QualifiedAutoCheck::registerMatchers(MatchFinder *Finder) { @@ -134,16 +136,30 @@ void QualifiedAutoCheck::registerMatchers(MatchFinder *Finder) { auto IsBoundToType = refersToType(equalsBoundNode("type")); auto UnlessFunctionType = unless(hasUnqualifiedDesugaredType(functionType())); - auto IsAutoDeducedToPointer = [](const std::vector<StringRef> &AllowedTypes, - const auto &...InnerMatchers) { - return autoType(hasDeducedType( - hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...))), - unless(hasUnqualifiedType( - matchers::matchesAnyListedTypeName(AllowedTypes, false))), - unless(pointerType(pointee(hasUnqualifiedType( - matchers::matchesAnyListedTypeName(AllowedTypes, false))))))); + + auto IsPointerType = [this](const auto &...InnerMatchers) { + if (this->IgnoreAliasing) { + return qualType( + hasUnqualifiedDesugaredType(pointerType(pointee(InnerMatchers...)))); + } else { + return qualType( + anyOf(qualType(pointerType(pointee(InnerMatchers...))), + qualType(substTemplateTypeParmType(hasReplacementType( + pointerType(pointee(InnerMatchers...))))))); + } }; + auto IsAutoDeducedToPointer = + [IsPointerType](const std::vector<StringRef> &AllowedTypes, + const auto &...InnerMatchers) { + return autoType(hasDeducedType( + IsPointerType(InnerMatchers...), + unless(hasUnqualifiedType( + matchers::matchesAnyListedTypeName(AllowedTypes, false))), + unless(pointerType(pointee(hasUnqualifiedType( + matchers::matchesAnyListedTypeName(AllowedTypes, false))))))); + }; + Finder->addMatcher( ExplicitSingleVarDecl( hasType(IsAutoDeducedToPointer(AllowedTypes, UnlessFunctionType)), diff --git a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h index 187a4cd..b5b713f 100644 --- a/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h +++ b/clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h @@ -32,6 +32,7 @@ public: private: const bool AddConstToQualified; const std::vector<StringRef> AllowedTypes; + const bool IgnoreAliasing; }; } // namespace clang::tidy::readability diff --git a/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py b/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py index 0f8ac73..7cd21af 100755 --- a/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py +++ b/clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py @@ -177,7 +177,7 @@ def main(): parser.add_argument( "-j", type=int, - default=1, + default=0, help="number of tidy instances to be run in parallel.", ) parser.add_argument( @@ -318,6 +318,7 @@ def main(): if max_task_count == 0: max_task_count = multiprocessing.cpu_count() max_task_count = min(len(lines_by_file), max_task_count) + print(f"Running clang-tidy in {max_task_count} threads...") combine_fixes = False export_fixes_dir = None diff --git a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py index 8741147..a3dca6c 100755 --- a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py +++ b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py @@ -548,7 +548,7 @@ async def main() -> None: files = {f for f in files if file_name_re.search(f)} print( - "Running clang-tidy for", + f"Running clang-tidy in {max_task} threads for", len(files), "files out of", number_files_in_database, diff --git a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp index 7f4ccca..e1c1bee 100644 --- a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp +++ b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp @@ -207,13 +207,9 @@ FormatStringConverter::FormatStringConverter( ArgsOffset(FormatArgOffset + 1), LangOpts(LO) { assert(ArgsOffset <= NumArgs); FormatExpr = llvm::dyn_cast<StringLiteral>( - Args[FormatArgOffset]->IgnoreImplicitAsWritten()); + Args[FormatArgOffset]->IgnoreUnlessSpelledInSource()); - if (!FormatExpr || !FormatExpr->isOrdinary()) { - // Function must have a narrow string literal as its first argument. - conversionNotPossible("first argument is not a narrow string literal"); - return; - } + assert(FormatExpr && FormatExpr->isOrdinary()); if (const std::optional<StringRef> MaybeMacroName = formatStringContainsUnreplaceableMacro(Call, FormatExpr, SM, PP); |