[flang][runtime] Make defined formatted I/O process format elementally (#74150)
[llvm-project.git] / libcxx / test / tools / clang_tidy_checks / uglify_attributes.cpp
blob7812b236f613c62426ed29bc15229227cc538746
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 //===----------------------------------------------------------------------===//
9 #include "clang-tidy/ClangTidyCheck.h"
10 #include "clang-tidy/ClangTidyModuleRegistry.h"
12 #include "uglify_attributes.hpp"
14 #include <algorithm>
15 #include <array>
16 #include <span>
17 #include <string_view>
19 namespace {
20 bool isUgly(std::string_view str) {
21 if (str.size() < 2)
22 return false;
23 if (str[0] == '_' && str[1] >= 'A' && str[1] <= 'Z')
24 return true;
25 return str.find("__") != std::string_view::npos;
28 // Starting with Clang 17 ToT C++23 support is provided by CPlusPlus23 instead
29 // of C++23 support is provided by CPlusPlus2b. To allow a smooth transition for
30 // libc++ use "reflection" to select the proper member. Since the change
31 // happens in the development cycle it's not possible to use #ifdefs.
32 template <class T>
33 bool CPlusPlus23(const T& lang_opts)
34 requires requires { T::CPlusPlus2b; }
36 return lang_opts.CPlusPlus2b;
39 template <class T>
40 bool CPlusPlus23(const T& lang_opts)
41 requires requires { T::CPlusPlus23; }
43 return lang_opts.CPlusPlus23;
46 std::vector<const char*> get_standard_attributes(const clang::LangOptions& lang_opts) {
47 std::vector<const char*> attributes;
49 if (lang_opts.CPlusPlus11) {
50 attributes.emplace_back("noreturn");
51 attributes.emplace_back("carries_dependency");
54 if (lang_opts.CPlusPlus14)
55 attributes.emplace_back("deprecated");
57 if (lang_opts.CPlusPlus17) {
58 attributes.emplace_back("fallthrough");
59 attributes.emplace_back("nodiscard");
60 attributes.emplace_back("maybe_unused");
63 if (lang_opts.CPlusPlus20) {
64 attributes.emplace_back("likely");
65 attributes.emplace_back("unlikely");
66 attributes.emplace_back("no_unique_address");
69 if (CPlusPlus23(lang_opts)) {
70 attributes.emplace_back("assume");
73 return attributes;
76 AST_MATCHER(clang::Attr, isPretty) {
77 if (Node.isKeywordAttribute() || !Node.getAttrName())
78 return false;
79 if (Node.isCXX11Attribute() && !Node.hasScope()) {
80 if (isUgly(Node.getAttrName()->getName()))
81 return false;
82 return !llvm::is_contained(
83 get_standard_attributes(Finder->getASTContext().getLangOpts()), Node.getAttrName()->getName());
85 if (Node.hasScope())
86 if (!isUgly(Node.getScopeName()->getName()))
87 return true;
88 return !isUgly(Node.getAttrName()->getName());
90 return false;
93 std::optional<std::string> getUglyfiedCXX11Attr(const clang::Attr& attr) {
94 // TODO: Don't emit FixItHints for attributes with `using` in them or emit correct fixes.
96 std::string attr_string;
97 if (attr.isClangScope())
98 attr_string += "_Clang::";
99 else if (attr.isGNUScope())
100 attr_string += "__gnu__::";
102 if (!attr.getAttrName()->getName().starts_with("__")) {
103 attr_string += "__";
104 attr_string += attr.getAttrName()->getName();
105 attr_string += "__";
106 } else {
107 attr_string += attr.getAttrName()->getName();
109 return std::move(attr_string);
112 std::optional<std::string> getUglyfiedGNUAttr(const clang::Attr& attr) {
113 return "__" + attr.getAttrName()->getName().str() + "__";
116 std::optional<std::string> getUglified(const clang::Attr& attr) {
117 if (attr.isCXX11Attribute()) {
118 return getUglyfiedCXX11Attr(attr);
119 } else if (attr.isGNUAttribute()) {
120 return getUglyfiedGNUAttr(attr);
123 return std::nullopt;
125 } // namespace
127 namespace libcpp {
128 uglify_attributes::uglify_attributes(llvm::StringRef name, clang::tidy::ClangTidyContext* context)
129 : clang::tidy::ClangTidyCheck(name, context) {}
131 void uglify_attributes::registerMatchers(clang::ast_matchers::MatchFinder* finder) {
132 using namespace clang::ast_matchers;
133 finder->addMatcher(attr(isPretty()).bind("normal_attribute"), this);
136 void uglify_attributes::check(const clang::ast_matchers::MatchFinder::MatchResult& result) {
137 if (const auto* attr = result.Nodes.getNodeAs<clang::Attr>("normal_attribute"); attr != nullptr) {
138 auto diagnostic = diag(attr->getLoc(), "Non-standard attributes should use the _Ugly spelling");
139 auto uglified = getUglified(*attr);
140 if (uglified.has_value()) {
141 diagnostic << clang::FixItHint::CreateReplacement(attr->getRange(), *uglified);
145 } // namespace libcpp