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