1 | //===--- AvoidNonConstGlobalVariablesCheck.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 "AvoidNonConstGlobalVariablesCheck.h" |
10 | #include "clang/AST/ASTContext.h" |
11 | #include "clang/ASTMatchers/ASTMatchFinder.h" |
12 | #include "clang/ASTMatchers/ASTMatchers.h" |
13 | |
14 | using namespace clang::ast_matchers; |
15 | |
16 | namespace clang::tidy::cppcoreguidelines { |
17 | |
18 | void AvoidNonConstGlobalVariablesCheck::registerMatchers(MatchFinder *Finder) { |
19 | auto GlobalContext = |
20 | varDecl(hasGlobalStorage(), |
21 | hasDeclContext(InnerMatcher: anyOf(namespaceDecl(), translationUnitDecl()))); |
22 | |
23 | auto GlobalVariable = varDecl( |
24 | GlobalContext, |
25 | unless(anyOf( |
26 | isConstexpr(), hasType(InnerMatcher: isConstQualified()), |
27 | hasType(InnerMatcher: referenceType())))); // References can't be changed, only the |
28 | // data they reference can be changed. |
29 | |
30 | auto GlobalReferenceToNonConst = |
31 | varDecl(GlobalContext, hasType(InnerMatcher: referenceType()), |
32 | unless(hasType(InnerMatcher: references(InnerMatcher: qualType(isConstQualified()))))); |
33 | |
34 | auto GlobalPointerToNonConst = varDecl( |
35 | GlobalContext, hasType(InnerMatcher: pointerType(pointee(unless(isConstQualified()))))); |
36 | |
37 | Finder->addMatcher(NodeMatch: GlobalVariable.bind(ID: "non-const_variable" ), Action: this); |
38 | Finder->addMatcher(NodeMatch: GlobalReferenceToNonConst.bind(ID: "indirection_to_non-const" ), |
39 | Action: this); |
40 | Finder->addMatcher(NodeMatch: GlobalPointerToNonConst.bind(ID: "indirection_to_non-const" ), |
41 | Action: this); |
42 | } |
43 | |
44 | void AvoidNonConstGlobalVariablesCheck::check( |
45 | const MatchFinder::MatchResult &Result) { |
46 | |
47 | if (const auto *Variable = |
48 | Result.Nodes.getNodeAs<VarDecl>(ID: "non-const_variable" )) { |
49 | diag(Variable->getLocation(), "variable %0 is non-const and globally " |
50 | "accessible, consider making it const" ) |
51 | << Variable; // FIXME: Add fix-it hint to Variable |
52 | // Don't return early, a non-const variable may also be a pointer or |
53 | // reference to non-const data. |
54 | } |
55 | |
56 | if (const auto *VD = |
57 | Result.Nodes.getNodeAs<VarDecl>(ID: "indirection_to_non-const" )) { |
58 | diag(VD->getLocation(), |
59 | "variable %0 provides global access to a non-const object; consider " |
60 | "making the %select{referenced|pointed-to}1 data 'const'" ) |
61 | << VD |
62 | << VD->getType()->isPointerType(); // FIXME: Add fix-it hint to Variable |
63 | } |
64 | } |
65 | |
66 | } // namespace clang::tidy::cppcoreguidelines |
67 | |