1 | //===--- AvoidUnderscoreInGoogletestNameCheck.cpp - clang-tidy --*- C++ -*-===// |
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 | |
9 | #include <string> |
10 | |
11 | #include "AvoidUnderscoreInGoogletestNameCheck.h" |
12 | #include "clang/AST/ASTContext.h" |
13 | #include "clang/ASTMatchers/ASTMatchers.h" |
14 | #include "clang/Frontend/CompilerInstance.h" |
15 | #include "clang/Lex/MacroArgs.h" |
16 | #include "clang/Lex/PPCallbacks.h" |
17 | #include "clang/Lex/Preprocessor.h" |
18 | |
19 | namespace clang::tidy::google::readability { |
20 | |
21 | constexpr llvm::StringLiteral KDisabledTestPrefix = "DISABLED_" ; |
22 | |
23 | // Determines whether the macro is a Googletest test macro. |
24 | static bool isGoogletestTestMacro(StringRef MacroName) { |
25 | static const llvm::StringSet<> MacroNames = {"TEST" , "TEST_F" , "TEST_P" , |
26 | "TYPED_TEST" , "TYPED_TEST_P" }; |
27 | return MacroNames.contains(key: MacroName); |
28 | } |
29 | |
30 | namespace { |
31 | |
32 | class AvoidUnderscoreInGoogletestNameCallback : public PPCallbacks { |
33 | public: |
34 | AvoidUnderscoreInGoogletestNameCallback( |
35 | Preprocessor *PP, AvoidUnderscoreInGoogletestNameCheck *Check) |
36 | : PP(PP), Check(Check) {} |
37 | |
38 | // Detects expansions of the TEST, TEST_F, TEST_P, TYPED_TEST, TYPED_TEST_P |
39 | // macros and checks that their arguments do not have any underscores. |
40 | void MacroExpands(const Token &MacroNameToken, |
41 | const MacroDefinition &MacroDefinition, SourceRange Range, |
42 | const MacroArgs *Args) override { |
43 | IdentifierInfo *NameIdentifierInfo = MacroNameToken.getIdentifierInfo(); |
44 | if (!NameIdentifierInfo) |
45 | return; |
46 | StringRef MacroName = NameIdentifierInfo->getName(); |
47 | if (!isGoogletestTestMacro(MacroName) || !Args || |
48 | Args->getNumMacroArguments() < 2) |
49 | return; |
50 | const Token *TestSuiteNameToken = Args->getUnexpArgument(Arg: 0); |
51 | const Token *TestNameToken = Args->getUnexpArgument(Arg: 1); |
52 | if (!TestSuiteNameToken || !TestNameToken) |
53 | return; |
54 | std::string TestSuiteNameMaybeDisabled = |
55 | PP->getSpelling(Tok: *TestSuiteNameToken); |
56 | StringRef TestSuiteName = TestSuiteNameMaybeDisabled; |
57 | TestSuiteName.consume_front(Prefix: KDisabledTestPrefix); |
58 | if (TestSuiteName.contains(C: '_')) |
59 | Check->diag(Loc: TestSuiteNameToken->getLocation(), |
60 | Description: "avoid using \"_\" in test suite name \"%0\" according to " |
61 | "Googletest FAQ" ) |
62 | << TestSuiteName; |
63 | |
64 | std::string TestNameMaybeDisabled = PP->getSpelling(Tok: *TestNameToken); |
65 | StringRef TestName = TestNameMaybeDisabled; |
66 | TestName.consume_front(Prefix: KDisabledTestPrefix); |
67 | if (TestName.contains(C: '_')) |
68 | Check->diag(Loc: TestNameToken->getLocation(), |
69 | Description: "avoid using \"_\" in test name \"%0\" according to " |
70 | "Googletest FAQ" ) |
71 | << TestName; |
72 | } |
73 | |
74 | private: |
75 | Preprocessor *PP; |
76 | AvoidUnderscoreInGoogletestNameCheck *Check; |
77 | }; |
78 | |
79 | } // namespace |
80 | |
81 | void AvoidUnderscoreInGoogletestNameCheck::registerPPCallbacks( |
82 | const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { |
83 | PP->addPPCallbacks( |
84 | C: std::make_unique<AvoidUnderscoreInGoogletestNameCallback>(args&: PP, args: this)); |
85 | } |
86 | |
87 | } // namespace clang::tidy::google::readability |
88 | |