clang-tools 24.0.0git
InvalidRegexPatternCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "clang/ASTMatchers/ASTMatchFinder.h"
11#include "llvm/Support/Regex.h"
12
13using namespace clang::ast_matchers;
14
16
18 auto IsConstllvmStringRef = qualType(
19 isConstQualified(), hasUnqualifiedDesugaredType(recordType(hasDeclaration(
20 cxxRecordDecl(hasName("::llvm::StringRef"))))));
21 auto IsConstStdString = qualType(
22 isConstQualified(), hasUnqualifiedDesugaredType(recordType(hasDeclaration(
23 cxxRecordDecl(hasName("::std::basic_string"))))));
24 auto GetStringLiteral =
25 ignoringImplicit(stringLiteral().bind("stringLiteral"));
26 auto GetStringLiteralFromObject =
27 ignoringImplicit(cxxConstructExpr(hasAnyArgument(GetStringLiteral)));
28 auto IsConstCharPtr = pointerType(pointee(builtinType(), isConstQualified()));
29 auto IsCharArray = qualType(
30 hasUnqualifiedDesugaredType(arrayType(hasElementType(builtinType()))));
31 auto IsStdStringView = qualType(hasUnqualifiedDesugaredType(recordType(
32 hasDeclaration(cxxRecordDecl(hasName("::std::basic_string_view"))))));
33 const auto HasStringContainerType =
34 hasType(qualType(anyOf(IsConstStdString, IsConstllvmStringRef,
35 IsStdStringView, IsConstCharPtr, IsCharArray)));
36 const auto GetString = anyOf(GetStringLiteralFromObject, GetStringLiteral);
37 const auto AnyCastedToStringRef = ignoringImplicit(
38 anyOf(stringLiteral().bind("stringLiteral"),
39 declRefExpr(
40 to(varDecl(HasStringContainerType, hasInitializer(GetString)))),
41 memberExpr(member(fieldDecl(HasStringContainerType,
42 hasInClassInitializer(GetString))))));
43
44 const auto IsRegexFlagsType = ignoringParenImpCasts(
45 anyOf(integerLiteral().bind("regexFlagsInt"),
46 declRefExpr(to(enumConstantDecl().bind("regexFlagEnum")))));
47 Finder->addMatcher(
48 cxxConstructExpr(
49 hasDeclaration(cxxConstructorDecl(ofClass(hasName("llvm::Regex")))),
50 hasArgument(0, ignoringImplicit(cxxConstructExpr(
51 hasDeclaration(cxxConstructorDecl(
52 ofClass(hasName("::llvm::StringRef")))),
53 hasArgument(0, AnyCastedToStringRef)))),
54 optionally(hasArgument(1, IsRegexFlagsType))),
55 this);
56}
57
58void InvalidRegexPatternCheck::check(const MatchFinder::MatchResult &Result) {
59 const auto *DetectedPattern =
60 Result.Nodes.getNodeAs<StringLiteral>("stringLiteral");
61 assert(DetectedPattern && "stringLiteral must be bound in matcher");
62
63 unsigned int Flag = llvm::Regex::RegexFlags::NoFlags;
64 if (const auto *FlagInt =
65 Result.Nodes.getNodeAs<IntegerLiteral>("regexFlagsInt"))
66 Flag = FlagInt->getValue().getZExtValue();
67 if (const auto *FlagEnum =
68 Result.Nodes.getNodeAs<EnumConstantDecl>("regexFlagEnum"))
69 Flag = FlagEnum->getInitVal().getZExtValue();
70 const llvm::Regex TestRegex(DetectedPattern->getString(), Flag);
71 std::string RegexError;
72 if (!TestRegex.isValid(RegexError))
73 diag(DetectedPattern->getBeginLoc(), "invalid regex pattern: %0")
74 << RegexError << DetectedPattern->getSourceRange();
75}
76
77} // namespace clang::tidy::llvm_check
void registerMatchers(ast_matchers::MatchFinder *Finder) override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override