-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[clang-tidy] do not diagnose array types within implicit instantiations of a template #132924
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,6 +39,53 @@ AST_MATCHER(clang::ParmVarDecl, isArgvOfMain) { | |
| return FD ? FD->isMain() : false; | ||
| } | ||
|
|
||
| template <typename TargetType, typename NodeType> | ||
| const TargetType *getAs(const NodeType *Node) { | ||
| if constexpr (std::is_same_v<NodeType, clang::DynTypedNode>) | ||
| return Node->template get<TargetType>(); | ||
| else | ||
| return llvm::dyn_cast<TargetType>(Node); | ||
| } | ||
|
|
||
| AST_MATCHER(clang::TypeLoc, isWithinImplicitTemplateInstantiation) { | ||
| const auto IsImplicitTemplateInstantiation = [](const auto *Node) { | ||
| const auto IsImplicitInstantiation = [](const auto *Node) { | ||
| return (Node != nullptr) && (Node->getTemplateSpecializationKind() == | ||
| TSK_ImplicitInstantiation); | ||
| }; | ||
| return (IsImplicitInstantiation(getAs<clang::CXXRecordDecl>(Node)) || | ||
| IsImplicitInstantiation(getAs<clang::FunctionDecl>(Node)) || | ||
| IsImplicitInstantiation(getAs<clang::VarDecl>(Node))); | ||
| }; | ||
|
|
||
| DynTypedNodeList ParentNodes = Finder->getASTContext().getParents(Node); | ||
| const clang::NamedDecl *ParentDecl = nullptr; | ||
| while (!ParentNodes.empty()) { | ||
| const DynTypedNode &ParentNode = ParentNodes[0]; | ||
| if (IsImplicitTemplateInstantiation(&ParentNode)) | ||
| return true; | ||
|
|
||
| // in case of a `NamedDecl` as parent node, it is more efficient to proceed | ||
| // with the upward traversal via DeclContexts (see below) instead of via | ||
| // parent nodes | ||
| if ((ParentDecl = ParentNode.template get<clang::NamedDecl>())) | ||
| break; | ||
|
|
||
| ParentNodes = Finder->getASTContext().getParents(ParentNode); | ||
| } | ||
|
|
||
| if (ParentDecl != nullptr) { | ||
| const clang::DeclContext *DeclContext = ParentDecl->getDeclContext(); | ||
| while (DeclContext != nullptr) { | ||
| if (IsImplicitTemplateInstantiation(DeclContext)) | ||
| return true; | ||
| DeclContext = DeclContext->getParent(); | ||
| } | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| } // namespace | ||
|
|
||
| AvoidCArraysCheck::AvoidCArraysCheck(StringRef Name, ClangTidyContext *Context) | ||
|
|
@@ -66,22 +113,38 @@ void AvoidCArraysCheck::registerMatchers(MatchFinder *Finder) { | |
| hasParent(varDecl(isExternC())), | ||
| hasParent(fieldDecl( | ||
| hasParent(recordDecl(isExternCContext())))), | ||
| hasAncestor(functionDecl(isExternC())))), | ||
| hasAncestor(functionDecl(isExternC())), | ||
| isWithinImplicitTemplateInstantiation())), | ||
|
||
| IgnoreStringArrayIfNeededMatcher) | ||
| .bind("typeloc"), | ||
| this); | ||
|
|
||
| Finder->addMatcher( | ||
| templateArgumentLoc(hasTypeLoc( | ||
| typeLoc(hasType(arrayType())).bind("template_arg_array_typeloc"))), | ||
| this); | ||
| } | ||
|
|
||
| void AvoidCArraysCheck::check(const MatchFinder::MatchResult &Result) { | ||
| const auto *ArrayType = Result.Nodes.getNodeAs<TypeLoc>("typeloc"); | ||
| TypeLoc ArrayTypeLoc{}; | ||
|
|
||
| if (const auto *MatchedTypeLoc = Result.Nodes.getNodeAs<TypeLoc>("typeloc")) | ||
| ArrayTypeLoc = *MatchedTypeLoc; | ||
|
|
||
| if (const auto *TemplateArgArrayTypeLoc = | ||
| Result.Nodes.getNodeAs<TypeLoc>("template_arg_array_typeloc")) | ||
| ArrayTypeLoc = *TemplateArgArrayTypeLoc; | ||
|
|
||
| assert(!ArrayTypeLoc.isNull()); | ||
|
|
||
| const bool IsInParam = | ||
| Result.Nodes.getNodeAs<ParmVarDecl>("param_decl") != nullptr; | ||
| const bool IsVLA = ArrayType->getTypePtr()->isVariableArrayType(); | ||
| const bool IsVLA = ArrayTypeLoc.getTypePtr()->isVariableArrayType(); | ||
| enum class RecommendType { Array, Vector, Span }; | ||
| llvm::SmallVector<const char *> RecommendTypes{}; | ||
| if (IsVLA) { | ||
| RecommendTypes.push_back("'std::vector'"); | ||
| } else if (ArrayType->getTypePtr()->isIncompleteArrayType() && IsInParam) { | ||
| } else if (ArrayTypeLoc.getTypePtr()->isIncompleteArrayType() && IsInParam) { | ||
| // in function parameter, we also don't know the size of | ||
| // IncompleteArrayType. | ||
| if (Result.Context->getLangOpts().CPlusPlus20) | ||
|
|
@@ -93,9 +156,11 @@ void AvoidCArraysCheck::check(const MatchFinder::MatchResult &Result) { | |
| } else { | ||
| RecommendTypes.push_back("'std::array'"); | ||
| } | ||
| diag(ArrayType->getBeginLoc(), | ||
|
|
||
| diag(ArrayTypeLoc.getBeginLoc(), | ||
| "do not declare %select{C-style|C VLA}0 arrays, use %1 instead") | ||
| << IsVLA << llvm::join(RecommendTypes, " or "); | ||
| << IsVLA << llvm::join(RecommendTypes, " or ") | ||
| << ArrayTypeLoc.getSourceRange(); | ||
| } | ||
|
|
||
| } // namespace clang::tidy::modernize | ||
Uh oh!
There was an error while loading. Please reload this page.