aboutsummaryrefslogtreecommitdiff
path: root/clang-tools-extra/clang-tidy
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clang-tidy')
-rw-r--r--clang-tools-extra/clang-tidy/ClangTidy.cpp5
-rw-r--r--clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp2
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp3
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt1
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp54
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.cpp180
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/InvalidEnumDefaultInitializationCheck.h31
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/SignedCharMisuseCheck.cpp18
-rw-r--r--clang-tools-extra/clang-tidy/bugprone/UnhandledSelfAssignmentCheck.cpp38
-rw-r--r--clang-tools-extra/clang-tidy/llvm/CMakeLists.txt2
-rw-r--r--clang-tools-extra/clang-tidy/llvm/LLVMTidyModule.cpp3
-rw-r--r--clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.cpp139
-rw-r--r--clang-tools-extra/clang-tidy/llvm/UseNewMLIROpBuilderCheck.h29
-rw-r--r--clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.cpp76
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseDesignatedInitializersCheck.cpp11
-rw-r--r--clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp4
-rw-r--r--clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp2
-rw-r--r--clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp5
-rw-r--r--clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.cpp34
-rw-r--r--clang-tools-extra/clang-tidy/readability/QualifiedAutoCheck.h1
-rwxr-xr-xclang-tools-extra/clang-tidy/tool/clang-tidy-diff.py3
-rwxr-xr-xclang-tools-extra/clang-tidy/tool/run-clang-tidy.py2
-rw-r--r--clang-tools-extra/clang-tidy/utils/Aliasing.cpp14
-rw-r--r--clang-tools-extra/clang-tidy/utils/Aliasing.h2
-rw-r--r--clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp8
25 files changed, 559 insertions, 108 deletions
diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp
index e84be04..4ae2864 100644
--- a/clang-tools-extra/clang-tidy/ClangTidy.cpp
+++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp
@@ -96,8 +96,7 @@ public:
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS)
: Files(FileSystemOptions(), std::move(BaseFS)),
DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), DiagOpts)),
- Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), DiagOpts,
- DiagPrinter),
+ Diags(DiagnosticIDs::create(), DiagOpts, DiagPrinter),
SourceMgr(Diags, Files), Context(Context), ApplyFixes(ApplyFixes) {
DiagOpts.ShowColors = Context.getOptions().UseColor.value_or(
llvm::sys::Process::StandardOutHasColors());
@@ -570,7 +569,7 @@ runClangTidy(clang::tidy::ClangTidyContext &Context,
ClangTidyDiagnosticConsumer DiagConsumer(Context, nullptr, true, ApplyAnyFix);
auto DiagOpts = std::make_unique<DiagnosticOptions>();
- DiagnosticsEngine DE(new DiagnosticIDs(), *DiagOpts, &DiagConsumer,
+ DiagnosticsEngine DE(DiagnosticIDs::create(), *DiagOpts, &DiagConsumer,
/*ShouldOwnClient=*/false);
Context.setDiagnosticsEngine(std::move(DiagOpts), &DE);
Tool.setDiagnosticConsumer(&DiagConsumer);
diff --git a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
index 2c17cd3..5e705f7 100644
--- a/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
+++ b/clang-tools-extra/clang-tidy/ExpandModularHeadersPPCallbacks.cpp
@@ -71,7 +71,7 @@ ExpandModularHeadersPPCallbacks::ExpandModularHeadersPPCallbacks(
InMemoryFs(new llvm::vfs::InMemoryFileSystem),
Sources(Compiler.getSourceManager()),
// Forward the new diagnostics to the original DiagnosticConsumer.
- Diags(new DiagnosticIDs, DiagOpts,
+ Diags(DiagnosticIDs::create(), DiagOpts,
new ForwardingDiagnosticConsumer(Compiler.getDiagnosticClient())),
LangOpts(Compiler.getLangOpts()), HSOpts(Compiler.getHeaderSearchOpts()) {
// Add a FileSystem containing the extra files needed in place of modular
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/InfiniteLoopCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
index 3c3024d..4b495e3 100644
--- a/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/InfiniteLoopCheck.cpp
@@ -49,7 +49,7 @@ static Matcher<Stmt> loopEndingStmt(Matcher<Stmt> Internal) {
}
/// Return whether `Var` was changed in `LoopStmt`.
-static bool isChanged(const Stmt *LoopStmt, const VarDecl *Var,
+static bool isChanged(const Stmt *LoopStmt, const ValueDecl *Var,
ASTContext *Context) {
if (const auto *ForLoop = dyn_cast<ForStmt>(LoopStmt))
return (ForLoop->getInc() &&
@@ -64,24 +64,35 @@ static bool isChanged(const Stmt *LoopStmt, const VarDecl *Var,
return ExprMutationAnalyzer(*LoopStmt, *Context).isMutated(Var);
}
+static bool isVarPossiblyChanged(const Decl *Func, const Stmt *LoopStmt,
+ const ValueDecl *VD, ASTContext *Context) {
+ const VarDecl *Var = nullptr;
+ if (const auto *VarD = dyn_cast<VarDecl>(VD)) {
+ Var = VarD;
+ } else if (const auto *BD = dyn_cast<BindingDecl>(VD)) {
+ if (const auto *DD = dyn_cast<DecompositionDecl>(BD->getDecomposedDecl()))
+ Var = DD;
+ }
+
+ if (!Var)
+ return false;
+
+ if (!Var->isLocalVarDeclOrParm() || Var->getType().isVolatileQualified())
+ return true;
+
+ if (!VD->getType().getTypePtr()->isIntegerType())
+ return true;
+
+ return hasPtrOrReferenceInFunc(Func, VD) || isChanged(LoopStmt, VD, Context);
+ // FIXME: Track references.
+}
+
/// Return whether `Cond` is a variable that is possibly changed in `LoopStmt`.
static bool isVarThatIsPossiblyChanged(const Decl *Func, const Stmt *LoopStmt,
const Stmt *Cond, ASTContext *Context) {
if (const auto *DRE = dyn_cast<DeclRefExpr>(Cond)) {
- if (const auto *Var = dyn_cast<VarDecl>(DRE->getDecl())) {
- if (!Var->isLocalVarDeclOrParm())
- return true;
-
- if (Var->getType().isVolatileQualified())
- return true;
-
- if (!Var->getType().getTypePtr()->isIntegerType())
- return true;
-
- return hasPtrOrReferenceInFunc(Func, Var) ||
- isChanged(LoopStmt, Var, Context);
- // FIXME: Track references.
- }
+ if (const auto *VD = dyn_cast<ValueDecl>(DRE->getDecl()))
+ return isVarPossiblyChanged(Func, LoopStmt, VD, Context);
} else if (isa<MemberExpr, CallExpr, ObjCIvarRefExpr, ObjCPropertyRefExpr,
ObjCMessageExpr>(Cond)) {
// FIXME: Handle MemberExpr.
@@ -123,6 +134,10 @@ static std::string getCondVarNames(const Stmt *Cond) {
if (const auto *DRE = dyn_cast<DeclRefExpr>(Cond)) {
if (const auto *Var = dyn_cast<VarDecl>(DRE->getDecl()))
return std::string(Var->getName());
+
+ if (const auto *BD = dyn_cast<BindingDecl>(DRE->getDecl())) {
+ return std::string(BD->getName());
+ }
}
std::string Result;
@@ -214,10 +229,17 @@ static bool overlap(ArrayRef<CallGraphNode *> SCC,
/// returns true iff `Cond` involves at least one static local variable.
static bool hasStaticLocalVariable(const Stmt *Cond) {
- if (const auto *DRE = dyn_cast<DeclRefExpr>(Cond))
+ if (const auto *DRE = dyn_cast<DeclRefExpr>(Cond)) {
if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
if (VD->isStaticLocal())
return true;
+
+ if (const auto *BD = dyn_cast<BindingDecl>(DRE->getDecl()))
+ if (const auto *DD = dyn_cast<DecompositionDecl>(BD->getDecomposedDecl()))
+ if (DD->isStaticLocal())
+ return true;
+ }
+
for (const Stmt *Child : Cond->children())
if (Child && hasStaticLocalVariable(Child))
return true;
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/bugprone/UnhandledSelfAssignmentCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnhandledSelfAssignmentCheck.cpp
index 1f432c4..c4c4267 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UnhandledSelfAssignmentCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UnhandledSelfAssignmentCheck.cpp
@@ -69,6 +69,28 @@ void UnhandledSelfAssignmentCheck::registerMatchers(MatchFinder *Finder) {
cxxMethodDecl(unless(hasDescendant(cxxMemberCallExpr(callee(cxxMethodDecl(
hasName("operator="), ofClass(equalsBoundNode("class"))))))));
+ // Checking that some kind of constructor is called and followed by a `swap`:
+ // T& operator=(const T& other) {
+ // T tmp{this->internal_data(), some, other, args};
+ // swap(tmp);
+ // return *this;
+ // }
+ const auto HasCopyAndSwap = cxxMethodDecl(
+ ofClass(cxxRecordDecl()),
+ hasBody(compoundStmt(
+ hasDescendant(
+ varDecl(hasType(cxxRecordDecl(equalsBoundNode("class"))))
+ .bind("tmp_var")),
+ hasDescendant(stmt(anyOf(
+ cxxMemberCallExpr(hasArgument(
+ 0, declRefExpr(to(varDecl(equalsBoundNode("tmp_var")))))),
+ callExpr(
+ callee(functionDecl(hasName("swap"))), argumentCountIs(2),
+ hasAnyArgument(
+ declRefExpr(to(varDecl(equalsBoundNode("tmp_var"))))),
+ hasAnyArgument(unaryOperator(has(cxxThisExpr()),
+ hasOperatorName("*"))))))))));
+
DeclarationMatcher AdditionalMatcher = cxxMethodDecl();
if (WarnOnlyIfThisHasSuspiciousField) {
// Matcher for standard smart pointers.
@@ -89,14 +111,14 @@ void UnhandledSelfAssignmentCheck::registerMatchers(MatchFinder *Finder) {
hasType(arrayType())))))));
}
- Finder->addMatcher(cxxMethodDecl(ofClass(cxxRecordDecl().bind("class")),
- isCopyAssignmentOperator(), IsUserDefined,
- HasReferenceParam, HasNoSelfCheck,
- unless(HasNonTemplateSelfCopy),
- unless(HasTemplateSelfCopy),
- HasNoNestedSelfAssign, AdditionalMatcher)
- .bind("copyAssignmentOperator"),
- this);
+ Finder->addMatcher(
+ cxxMethodDecl(
+ ofClass(cxxRecordDecl().bind("class")), isCopyAssignmentOperator(),
+ IsUserDefined, HasReferenceParam, HasNoSelfCheck,
+ unless(HasNonTemplateSelfCopy), unless(HasTemplateSelfCopy),
+ unless(HasCopyAndSwap), HasNoNestedSelfAssign, AdditionalMatcher)
+ .bind("copyAssignmentOperator"),
+ this);
}
void UnhandledSelfAssignmentCheck::check(
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/misc/HeaderIncludeCycleCheck.cpp b/clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.cpp
index 21d443a..1f6ceda 100644
--- a/clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.cpp
@@ -13,8 +13,8 @@
#include "clang/Lex/Preprocessor.h"
#include "llvm/Support/Regex.h"
#include <algorithm>
-#include <deque>
#include <optional>
+#include <vector>
using namespace clang::ast_matchers;
@@ -23,8 +23,8 @@ namespace clang::tidy::misc {
namespace {
struct Include {
- FileID Id;
- llvm::StringRef Name;
+ const FileEntry *File;
+ StringRef Name;
SourceLocation Loc;
};
@@ -50,31 +50,27 @@ public:
if (Reason != EnterFile && Reason != ExitFile)
return;
- FileID Id = SM.getFileID(Loc);
+ const FileID Id = SM.getFileID(Loc);
if (Id.isInvalid())
return;
+ const FileEntry *NewFile = SM.getFileEntryForID(Id);
+ const FileEntry *PrevFile = SM.getFileEntryForID(PrevFID);
+
if (Reason == ExitFile) {
- if ((Files.size() > 1U) && (Files.back().Id == PrevFID) &&
- (Files[Files.size() - 2U].Id == Id))
+ if ((Files.size() > 1U) && (Files.back().File == PrevFile) &&
+ (Files[Files.size() - 2U].File == NewFile))
Files.pop_back();
return;
}
- if (!Files.empty() && Files.back().Id == Id)
+ if (!Files.empty() && Files.back().File == NewFile)
return;
- std::optional<llvm::StringRef> FilePath = SM.getNonBuiltinFilenameForID(Id);
- llvm::StringRef FileName =
- FilePath ? llvm::sys::path::filename(*FilePath) : llvm::StringRef();
-
- if (!NextToEnter)
- NextToEnter = Include{Id, FileName, SourceLocation()};
-
- assert(NextToEnter->Name == FileName);
- NextToEnter->Id = Id;
- Files.emplace_back(*NextToEnter);
- NextToEnter.reset();
+ const std::optional<StringRef> FilePath = SM.getNonBuiltinFilenameForID(Id);
+ const StringRef FileName =
+ FilePath ? llvm::sys::path::filename(*FilePath) : StringRef();
+ Files.push_back({NewFile, FileName, std::exchange(NextToEnter, {})});
}
void InclusionDirective(SourceLocation, const Token &, StringRef FilePath,
@@ -85,36 +81,26 @@ public:
if (FileType != clang::SrcMgr::C_User)
return;
- llvm::StringRef FileName = llvm::sys::path::filename(FilePath);
- NextToEnter = {FileID(), FileName, Range.getBegin()};
+ NextToEnter = Range.getBegin();
if (!File)
return;
- FileID Id = SM.translateFile(*File);
- if (Id.isInvalid())
- return;
-
- checkForDoubleInclude(Id, FileName, Range.getBegin());
- }
-
- void EndOfMainFile() override {
- if (!Files.empty() && Files.back().Id == SM.getMainFileID())
- Files.pop_back();
-
- assert(Files.empty());
+ checkForDoubleInclude(&File->getFileEntry(),
+ llvm::sys::path::filename(FilePath),
+ Range.getBegin());
}
- void checkForDoubleInclude(FileID Id, llvm::StringRef FileName,
+ void checkForDoubleInclude(const FileEntry *File, StringRef FileName,
SourceLocation Loc) {
- auto It =
- std::find_if(Files.rbegin(), Files.rend(),
- [&](const Include &Entry) { return Entry.Id == Id; });
+ const auto It =
+ llvm::find_if(llvm::reverse(Files),
+ [&](const Include &Entry) { return Entry.File == File; });
if (It == Files.rend())
return;
- const std::optional<StringRef> FilePath = SM.getNonBuiltinFilenameForID(Id);
- if (!FilePath || isFileIgnored(*FilePath))
+ const StringRef FilePath = File->tryGetRealPathName();
+ if (FilePath.empty() || isFileIgnored(FilePath))
return;
if (It == Files.rbegin()) {
@@ -144,9 +130,19 @@ public:
});
}
+#ifndef NDEBUG
+ void EndOfMainFile() override {
+ if (!Files.empty() &&
+ Files.back().File == SM.getFileEntryForID(SM.getMainFileID()))
+ Files.pop_back();
+
+ assert(Files.empty());
+ }
+#endif
+
private:
- std::deque<Include> Files;
- std::optional<Include> NextToEnter;
+ std::vector<Include> Files;
+ SourceLocation NextToEnter;
HeaderIncludeCycleCheck &Check;
const SourceManager &SM;
std::vector<llvm::Regex> IgnoredFilesRegexes;
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/plugin/ClangTidyPlugin.cpp b/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp
index 651a63b..195418d 100644
--- a/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp
+++ b/clang-tools-extra/clang-tidy/plugin/ClangTidyPlugin.cpp
@@ -41,7 +41,7 @@ public:
new ClangTidyDiagnosticConsumer(*Context, &Compiler.getDiagnostics());
auto DiagOpts = std::make_unique<DiagnosticOptions>();
auto DiagEngine = std::make_unique<DiagnosticsEngine>(
- new DiagnosticIDs, *DiagOpts, DiagConsumer);
+ DiagnosticIDs::create(), *DiagOpts, DiagConsumer);
Context->setDiagnosticsEngine(std::move(DiagOpts), DiagEngine.get());
// Create the AST consumer.
diff --git a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
index 9c2f27f0..aaa2336 100644
--- a/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/portability/TemplateVirtualMemberFunctionCheck.cpp
@@ -18,10 +18,11 @@ AST_MATCHER(CXXMethodDecl, isUsed) { return Node.isUsed(); }
void TemplateVirtualMemberFunctionCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
- cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
+ cxxMethodDecl(isVirtual(),
+ ofClass(classTemplateSpecializationDecl(
unless(isExplicitTemplateSpecialization()))
.bind("specialization")),
- isVirtual(), unless(isUsed()),
+ unless(isUsed()), unless(isPure()),
unless(cxxDestructorDecl(isDefaulted())))
.bind("method"),
this);
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/Aliasing.cpp b/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
index 2facf06..cbe4873 100644
--- a/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
+++ b/clang-tools-extra/clang-tidy/utils/Aliasing.cpp
@@ -14,14 +14,14 @@
namespace clang::tidy::utils {
/// Return whether \p S is a reference to the declaration of \p Var.
-static bool isAccessForVar(const Stmt *S, const VarDecl *Var) {
+static bool isAccessForVar(const Stmt *S, const ValueDecl *Var) {
if (const auto *DRE = dyn_cast<DeclRefExpr>(S))
return DRE->getDecl() == Var;
return false;
}
-static bool capturesByRef(const CXXRecordDecl *RD, const VarDecl *Var) {
+static bool capturesByRef(const CXXRecordDecl *RD, const ValueDecl *Var) {
return llvm::any_of(RD->captures(), [Var](const LambdaCapture &C) {
return C.capturesVariable() && C.getCaptureKind() == LCK_ByRef &&
C.getCapturedVar() == Var;
@@ -29,9 +29,9 @@ static bool capturesByRef(const CXXRecordDecl *RD, const VarDecl *Var) {
}
/// Return whether \p Var has a pointer or reference in \p S.
-static bool isPtrOrReferenceForVar(const Stmt *S, const VarDecl *Var) {
+static bool isPtrOrReferenceForVar(const Stmt *S, const ValueDecl *Var) {
// Treat block capture by reference as a form of taking a reference.
- if (Var->isEscapingByref())
+ if (const auto *VD = dyn_cast<VarDecl>(Var); VD && VD->isEscapingByref())
return true;
if (const auto *DS = dyn_cast<DeclStmt>(S)) {
@@ -61,7 +61,7 @@ static bool isPtrOrReferenceForVar(const Stmt *S, const VarDecl *Var) {
}
/// Return whether \p Var has a pointer or reference in \p S.
-static bool hasPtrOrReferenceInStmt(const Stmt *S, const VarDecl *Var) {
+static bool hasPtrOrReferenceInStmt(const Stmt *S, const ValueDecl *Var) {
if (isPtrOrReferenceForVar(S, Var))
return true;
@@ -77,7 +77,7 @@ static bool hasPtrOrReferenceInStmt(const Stmt *S, const VarDecl *Var) {
}
static bool refersToEnclosingLambdaCaptureByRef(const Decl *Func,
- const VarDecl *Var) {
+ const ValueDecl *Var) {
const auto *MD = dyn_cast<CXXMethodDecl>(Func);
if (!MD)
return false;
@@ -89,7 +89,7 @@ static bool refersToEnclosingLambdaCaptureByRef(const Decl *Func,
return capturesByRef(RD, Var);
}
-bool hasPtrOrReferenceInFunc(const Decl *Func, const VarDecl *Var) {
+bool hasPtrOrReferenceInFunc(const Decl *Func, const ValueDecl *Var) {
return hasPtrOrReferenceInStmt(Func->getBody(), Var) ||
refersToEnclosingLambdaCaptureByRef(Func, Var);
}
diff --git a/clang-tools-extra/clang-tidy/utils/Aliasing.h b/clang-tools-extra/clang-tidy/utils/Aliasing.h
index 7dad16f..6c0763b 100644
--- a/clang-tools-extra/clang-tidy/utils/Aliasing.h
+++ b/clang-tools-extra/clang-tidy/utils/Aliasing.h
@@ -25,7 +25,7 @@ namespace clang::tidy::utils {
/// For `f()` and `n` the function returns ``true`` because `p` is a
/// pointer to `n` created in `f()`.
-bool hasPtrOrReferenceInFunc(const Decl *Func, const VarDecl *Var);
+bool hasPtrOrReferenceInFunc(const Decl *Func, const ValueDecl *Var);
} // namespace clang::tidy::utils
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);