1 | //===--- DispatchOnceNonstaticCheck.cpp - clang-tidy ----------------------===// |
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 "DispatchOnceNonstaticCheck.h" |
10 | #include "clang/AST/ASTContext.h" |
11 | #include "clang/AST/Decl.h" |
12 | #include "clang/AST/DeclObjC.h" |
13 | #include "clang/ASTMatchers/ASTMatchFinder.h" |
14 | #include "clang/ASTMatchers/ASTMatchers.h" |
15 | #include "clang/Basic/Diagnostic.h" |
16 | |
17 | using namespace clang::ast_matchers; |
18 | |
19 | namespace clang::tidy::darwin { |
20 | |
21 | void DispatchOnceNonstaticCheck::registerMatchers(MatchFinder *Finder) { |
22 | // Find variables without static or global storage. VarDecls do not include |
23 | // struct/class members, which are FieldDecls. |
24 | Finder->addMatcher( |
25 | NodeMatch: varDecl(hasLocalStorage(), hasType(InnerMatcher: asString(Name: "dispatch_once_t" ))) |
26 | .bind(ID: "non-static-var" ), |
27 | Action: this); |
28 | |
29 | // Members of structs or classes might be okay, if the use is at static or |
30 | // global scope. These will be ignored for now. But ObjC ivars can be |
31 | // flagged immediately, since they cannot be static. |
32 | Finder->addMatcher( |
33 | NodeMatch: objcIvarDecl(hasType(InnerMatcher: asString(Name: "dispatch_once_t" ))).bind(ID: "ivar" ), Action: this); |
34 | } |
35 | |
36 | void DispatchOnceNonstaticCheck::check(const MatchFinder::MatchResult &Result) { |
37 | if (const auto *VD = Result.Nodes.getNodeAs<VarDecl>(ID: "non-static-var" )) { |
38 | if (const auto *PD = dyn_cast<ParmVarDecl>(Val: VD)) { |
39 | // Catch function/method parameters, as any dispatch_once_t should be |
40 | // passed by pointer instead. |
41 | diag(PD->getTypeSpecStartLoc(), |
42 | "dispatch_once_t variables must have static or global storage " |
43 | "duration; function parameters should be pointer references" ); |
44 | } else { |
45 | diag(VD->getTypeSpecStartLoc(), "dispatch_once_t variables must have " |
46 | "static or global storage duration" ) |
47 | << FixItHint::CreateInsertion(InsertionLoc: VD->getTypeSpecStartLoc(), Code: "static " ); |
48 | } |
49 | } |
50 | |
51 | if (const auto *D = Result.Nodes.getNodeAs<ObjCIvarDecl>(ID: "ivar" )) { |
52 | diag(D->getTypeSpecStartLoc(), |
53 | "dispatch_once_t variables must have static or global storage " |
54 | "duration and cannot be Objective-C instance variables" ); |
55 | } |
56 | } |
57 | |
58 | } // namespace clang::tidy::darwin |
59 | |