brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.9 KiB · 38bf620 Raw
111 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 "hide_from_abi.hpp"13 14namespace {15AST_MATCHER(clang::ClassTemplateDecl, hasFullSpecializations) { return !Node.specializations().empty(); }16AST_MATCHER(clang::CXXRecordDecl, isTrivial) { return Node.isTrivial(); }17} // namespace18 19namespace libcpp {20hide_from_abi::hide_from_abi(llvm::StringRef name, clang::tidy::ClangTidyContext* context)21    : clang::tidy::ClangTidyCheck(name, context) {}22 23void hide_from_abi::registerMatchers(clang::ast_matchers::MatchFinder* finder) {24  using namespace clang::ast_matchers;25 26  auto has_hide_from_abi_attr = anyOf(hasAttr(clang::attr::Visibility), hasAttr(clang::attr::AbiTag));27 28  finder->addMatcher(29      functionDecl(30          unless(anyOf(31              // These functions can't be marked `[[gnu::always_inline]]` for various reasons,32              // so we can't mark them `_LIBCPP_HIDE_FROM_ABI`. These functions are ignored in33              // all namespaces. Checking the qualified name is a lot harder and these names34              // should result in very few (if any) false-negatives. This is also just a35              // temporary work-around until we can mark functions as HIDE_FROM_ABI without36              // having to add `[[gnu::always_inline]]` with GCC.37              hasAnyName("__introsort",38                         "__inplace_merge",39                         "__libcpp_snprintf_l",40                         "__libcpp_asprintf_l",41                         "__libcpp_sscanf_l",42                         "__tree_sub_invariant",43                         "__stable_sort_move",44                         "__stable_sort",45                         "__stable_partition",46                         "__lock_first",47                         "__stable_partition_impl"),48              has_hide_from_abi_attr,49              cxxMethodDecl(), // We have explicitly instantiated classes and some of their methods don't have these attributes50              isDeleted(),51              isConsteval())),52          isDefinition())53          .bind("hide_from_abi_on_free_function"),54      this);55 56  auto on_trivial = allOf(57      unless(isImplicit()), isDefaulted(), unless(ofClass(hasAncestor(classTemplateDecl()))), ofClass(isTrivial()));58 59  // TODO: find a better way to check for explicit instantiations. Currently, every template that has a full60  // specialization is ignored. For example, vector is ignored because we instantiate vector<double>61  // in discrete_distribution.62  finder->addMatcher(63      cxxMethodDecl(64          unless(anyOf(65              has_hide_from_abi_attr,66              isDeleted(),67              isImplicit(),68              hasAncestor(cxxRecordDecl(isLambda())),69              ofClass(anyOf(hasAncestor(classTemplateDecl(hasFullSpecializations())),70                            hasAnyName("basic_filebuf",71                                       "basic_ifstream",72                                       "basic_ofstream", // These are in the dylib in ABIv273                                       // TODO: fix the matcher to catch `sentry` instantiation.74                                       "sentry"))),75              isConsteval(),76              hasParent(classTemplateSpecializationDecl()),77              on_trivial)),78          isDefinition())79          .bind("hide_from_abi_on_member_function"),80      this);81 82  finder->addMatcher(83      cxxMethodDecl(has_hide_from_abi_attr, on_trivial).bind("hide_from_abi_on_defaulted_smf_in_trivial_class"), this);84}85 86void hide_from_abi::check(const clang::ast_matchers::MatchFinder::MatchResult& result) {87  if (const auto* call = result.Nodes.getNodeAs<clang::FunctionDecl>("hide_from_abi_on_free_function");88      call != nullptr) {89    diag(call->getBeginLoc(), "_LIBCPP_HIDE_FROM_ABI is missing");90  }91 92  // The rest gets ignored in C++03 because it is subtly different in some cases.93  // e.g. we change the definition of default constructors in some cases94  // TODO: check whether we can remove thse differences95  if (!result.Context->getLangOpts().CPlusPlus11)96    return;97 98  if (const auto* call = result.Nodes.getNodeAs<clang::CXXMethodDecl>("hide_from_abi_on_member_function");99      call != nullptr) {100    diag(call->getLocation(), "_LIBCPP_HIDE_FROM_ABI or _LIBCPP_HIDE_FROM_ABI_VIRTUAL is missing");101  }102 103  if (const auto* call =104          result.Nodes.getNodeAs<clang::CXXMethodDecl>("hide_from_abi_on_defaulted_smf_in_trivial_class");105      call != nullptr) {106    diag(call->getLocation(),107         "_LIBCPP_HIDE_FROM_ABI should not be used for special member functions in trivial classes");108  }109}110} // namespace libcpp111