brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.1 KiB · 24bacde Raw
135 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang-tidy/ClangTidyCheck.h"10#include "clang-tidy/ClangTidyModuleRegistry.h"11 12#include "uglify_attributes.hpp"13#include "utilities.hpp"14 15#include <optional>16 17namespace {18 19// Starting with Clang 17 ToT C++23 support is provided by CPlusPlus23 instead20// of C++23 support is provided by CPlusPlus2b. To allow a smooth transition for21// libc++ use "reflection" to select the proper member. Since the change22// happens in the development cycle it's not possible to use #ifdefs.23template <class T>24bool CPlusPlus23(const T& lang_opts)25  requires requires { T::CPlusPlus2b; }26{27  return lang_opts.CPlusPlus2b;28}29 30template <class T>31bool CPlusPlus23(const T& lang_opts)32  requires requires { T::CPlusPlus23; }33{34  return lang_opts.CPlusPlus23;35}36 37std::vector<const char*> get_standard_attributes(const clang::LangOptions& lang_opts) {38  std::vector<const char*> attributes;39 40  if (lang_opts.CPlusPlus11) {41    attributes.emplace_back("noreturn");42    attributes.emplace_back("carries_dependency");43  }44 45  if (lang_opts.CPlusPlus14)46    attributes.emplace_back("deprecated");47 48  if (lang_opts.CPlusPlus17) {49    attributes.emplace_back("fallthrough");50    attributes.emplace_back("nodiscard");51    attributes.emplace_back("maybe_unused");52  }53 54  if (lang_opts.CPlusPlus20) {55    attributes.emplace_back("likely");56    attributes.emplace_back("unlikely");57    attributes.emplace_back("no_unique_address");58  }59 60  if (CPlusPlus23(lang_opts)) {61    attributes.emplace_back("assume");62  }63 64  return attributes;65}66 67AST_MATCHER(clang::Attr, isPretty) {68  if (Node.isKeywordAttribute() || !Node.getAttrName())69    return false;70  if (Node.isCXX11Attribute() && !Node.hasScope()) {71    if (is_ugly_name(Node.getAttrName()->getName()))72      return false;73    return !llvm::is_contained(74        get_standard_attributes(Finder->getASTContext().getLangOpts()), Node.getAttrName()->getName());75  }76  if (Node.hasScope())77    if (!is_ugly_name(Node.getScopeName()->getName()))78      return true;79  return !is_ugly_name(Node.getAttrName()->getName());80}81 82std::optional<std::string> getUglyfiedCXX11Attr(const clang::Attr& attr) {83  // TODO: Don't emit FixItHints for attributes with `using` in them or emit correct fixes.84 85  std::string attr_string;86  if (attr.isClangScope())87    attr_string += "_Clang::";88  else if (attr.isGNUScope())89    attr_string += "__gnu__::";90 91  if (!attr.getAttrName()->getName().starts_with("__")) {92    attr_string += "__";93    attr_string += attr.getAttrName()->getName();94    attr_string += "__";95  } else {96    attr_string += attr.getAttrName()->getName();97  }98  return std::move(attr_string);99}100 101std::optional<std::string> getUglyfiedGNUAttr(const clang::Attr& attr) {102  return "__" + attr.getAttrName()->getName().str() + "__";103}104 105std::optional<std::string> getUglified(const clang::Attr& attr) {106  if (attr.isCXX11Attribute()) {107    return getUglyfiedCXX11Attr(attr);108  } else if (attr.isGNUAttribute()) {109    return getUglyfiedGNUAttr(attr);110  }111 112  return std::nullopt;113}114} // namespace115 116namespace libcpp {117uglify_attributes::uglify_attributes(llvm::StringRef name, clang::tidy::ClangTidyContext* context)118    : clang::tidy::ClangTidyCheck(name, context) {}119 120void uglify_attributes::registerMatchers(clang::ast_matchers::MatchFinder* finder) {121  using namespace clang::ast_matchers;122  finder->addMatcher(attr(isPretty()).bind("normal_attribute"), this);123}124 125void uglify_attributes::check(const clang::ast_matchers::MatchFinder::MatchResult& result) {126  if (const auto* attr = result.Nodes.getNodeAs<clang::Attr>("normal_attribute"); attr != nullptr) {127    auto diagnostic = diag(attr->getLoc(), "Non-standard attributes should use the _Ugly spelling");128    auto uglified   = getUglified(*attr);129    if (uglified.has_value()) {130      diagnostic << clang::FixItHint::CreateReplacement(attr->getRange(), *uglified);131    }132  }133}134} // namespace libcpp135