brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.7 KiB · 6ba1408 Raw
256 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// A checker for magic numbers: integer or floating point literals embedded10// in the code, outside the definition of a constant or an enumeration.11//12//===----------------------------------------------------------------------===//13 14#include "MagicNumbersCheck.h"15#include "../utils/OptionsUtils.h"16#include "clang/AST/ASTContext.h"17#include "clang/AST/ASTTypeTraits.h"18#include "clang/AST/Type.h"19#include "clang/ASTMatchers/ASTMatchFinder.h"20#include "llvm/ADT/STLExtras.h"21 22using namespace clang::ast_matchers;23 24namespace clang {25 26static bool isUsedToInitializeAConstant(const MatchFinder::MatchResult &Result,27                                        const DynTypedNode &Node) {28  const auto *AsDecl = Node.get<DeclaratorDecl>();29  if (AsDecl) {30    if (AsDecl->getType().isConstQualified())31      return true;32 33    return AsDecl->isImplicit();34  }35 36  if (Node.get<EnumConstantDecl>())37    return true;38 39  return llvm::any_of(Result.Context->getParents(Node),40                      [&Result](const DynTypedNode &Parent) {41                        return isUsedToInitializeAConstant(Result, Parent);42                      });43}44 45static bool isUsedToDefineATypeAlias(const MatchFinder::MatchResult &Result,46                                     const DynTypedNode &Node) {47  if (Node.get<TypeAliasDecl>() || Node.get<TypedefNameDecl>())48    return true;49 50  return llvm::any_of(Result.Context->getParents(Node),51                      [&Result](const DynTypedNode &Parent) {52                        return isUsedToDefineATypeAlias(Result, Parent);53                      });54}55 56static bool isUsedToDefineABitField(const MatchFinder::MatchResult &Result,57                                    const DynTypedNode &Node) {58  const auto *AsFieldDecl = Node.get<FieldDecl>();59  if (AsFieldDecl && AsFieldDecl->isBitField())60    return true;61 62  return llvm::any_of(Result.Context->getParents(Node),63                      [&Result](const DynTypedNode &Parent) {64                        return isUsedToDefineABitField(Result, Parent);65                      });66}67 68namespace tidy::readability {69 70const char DefaultIgnoredIntegerValues[] = "1;2;3;4;";71const char DefaultIgnoredFloatingPointValues[] = "1.0;100.0;";72 73MagicNumbersCheck::MagicNumbersCheck(StringRef Name, ClangTidyContext *Context)74    : ClangTidyCheck(Name, Context),75      IgnoreAllFloatingPointValues(76          Options.get("IgnoreAllFloatingPointValues", false)),77      IgnoreBitFieldsWidths(Options.get("IgnoreBitFieldsWidths", true)),78      IgnorePowersOf2IntegerValues(79          Options.get("IgnorePowersOf2IntegerValues", false)),80      IgnoreTypeAliases(Options.get("IgnoreTypeAliases", false)),81      IgnoreUserDefinedLiterals(82          Options.get("IgnoreUserDefinedLiterals", false)),83      RawIgnoredIntegerValues(84          Options.get("IgnoredIntegerValues", DefaultIgnoredIntegerValues)),85      RawIgnoredFloatingPointValues(Options.get(86          "IgnoredFloatingPointValues", DefaultIgnoredFloatingPointValues)) {87  // Process the set of ignored integer values.88  const std::vector<StringRef> IgnoredIntegerValuesInput =89      utils::options::parseStringList(RawIgnoredIntegerValues);90  IgnoredIntegerValues.resize(IgnoredIntegerValuesInput.size());91  llvm::transform(IgnoredIntegerValuesInput, IgnoredIntegerValues.begin(),92                  [](StringRef Value) {93                    int64_t Res = 0;94                    Value.getAsInteger(10, Res);95                    return Res;96                  });97  llvm::sort(IgnoredIntegerValues);98 99  if (!IgnoreAllFloatingPointValues) {100    // Process the set of ignored floating point values.101    const std::vector<StringRef> IgnoredFloatingPointValuesInput =102        utils::options::parseStringList(RawIgnoredFloatingPointValues);103    IgnoredFloatingPointValues.reserve(IgnoredFloatingPointValuesInput.size());104    IgnoredDoublePointValues.reserve(IgnoredFloatingPointValuesInput.size());105    for (const auto &InputValue : IgnoredFloatingPointValuesInput) {106      llvm::APFloat FloatValue(llvm::APFloat::IEEEsingle());107      auto StatusOrErr =108          FloatValue.convertFromString(InputValue, DefaultRoundingMode);109      assert(StatusOrErr && "Invalid floating point representation");110      consumeError(StatusOrErr.takeError());111      IgnoredFloatingPointValues.push_back(FloatValue.convertToFloat());112 113      llvm::APFloat DoubleValue(llvm::APFloat::IEEEdouble());114      StatusOrErr =115          DoubleValue.convertFromString(InputValue, DefaultRoundingMode);116      assert(StatusOrErr && "Invalid floating point representation");117      consumeError(StatusOrErr.takeError());118      IgnoredDoublePointValues.push_back(DoubleValue.convertToDouble());119    }120    llvm::sort(IgnoredFloatingPointValues);121    llvm::sort(IgnoredDoublePointValues);122  }123}124 125void MagicNumbersCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {126  Options.store(Opts, "IgnoreAllFloatingPointValues",127                IgnoreAllFloatingPointValues);128  Options.store(Opts, "IgnoreBitFieldsWidths", IgnoreBitFieldsWidths);129  Options.store(Opts, "IgnorePowersOf2IntegerValues",130                IgnorePowersOf2IntegerValues);131  Options.store(Opts, "IgnoreTypeAliases", IgnoreTypeAliases);132  Options.store(Opts, "IgnoreUserDefinedLiterals", IgnoreUserDefinedLiterals);133  Options.store(Opts, "IgnoredIntegerValues", RawIgnoredIntegerValues);134  Options.store(Opts, "IgnoredFloatingPointValues",135                RawIgnoredFloatingPointValues);136}137 138void MagicNumbersCheck::registerMatchers(MatchFinder *Finder) {139  Finder->addMatcher(integerLiteral().bind("integer"), this);140  if (!IgnoreAllFloatingPointValues)141    Finder->addMatcher(floatLiteral().bind("float"), this);142}143 144void MagicNumbersCheck::check(const MatchFinder::MatchResult &Result) {145  const TraversalKindScope RAII(*Result.Context, TK_AsIs);146 147  checkBoundMatch<IntegerLiteral>(Result, "integer");148  checkBoundMatch<FloatingLiteral>(Result, "float");149}150 151bool MagicNumbersCheck::isConstant(const MatchFinder::MatchResult &Result,152                                   const Expr &ExprResult) const {153  return llvm::any_of(154      Result.Context->getParents(ExprResult),155      [this, &Result](const DynTypedNode &Parent) {156        if (isUsedToInitializeAConstant(Result, Parent))157          return true;158 159        if (IgnoreTypeAliases && isUsedToDefineATypeAlias(Result, Parent))160          return true;161 162        // Ignore this instance, because this matches an163        // expanded class enumeration value.164        if (Parent.get<CStyleCastExpr>() &&165            llvm::any_of(166                Result.Context->getParents(Parent),167                [](const DynTypedNode &GrandParent) {168                  return GrandParent.get<SubstNonTypeTemplateParmExpr>() !=169                         nullptr;170                }))171          return true;172 173        // Ignore this instance, because this match reports the174        // location where the template is defined, not where it175        // is instantiated.176        if (Parent.get<SubstNonTypeTemplateParmExpr>())177          return true;178 179        // Don't warn on string user defined literals:180        // std::string s = "Hello World"s;181        if (const auto *UDL = Parent.get<UserDefinedLiteral>())182          if (UDL->getLiteralOperatorKind() == UserDefinedLiteral::LOK_String)183            return true;184 185        return false;186      });187}188 189bool MagicNumbersCheck::isIgnoredValue(const IntegerLiteral *Literal) const {190  if (Literal->getType()->isBitIntType()) {191    return true;192  }193  const llvm::APInt IntValue = Literal->getValue();194  const int64_t Value = IntValue.getZExtValue();195  if (Value == 0)196    return true;197 198  if (IgnorePowersOf2IntegerValues && IntValue.isPowerOf2())199    return true;200 201  return llvm::binary_search(IgnoredIntegerValues, Value);202}203 204bool MagicNumbersCheck::isIgnoredValue(const FloatingLiteral *Literal) const {205  const llvm::APFloat FloatValue = Literal->getValue();206  if (FloatValue.isZero())207    return true;208 209  if (&FloatValue.getSemantics() == &llvm::APFloat::IEEEsingle()) {210    const float Value = FloatValue.convertToFloat();211    return llvm::binary_search(IgnoredFloatingPointValues, Value);212  }213 214  if (&FloatValue.getSemantics() == &llvm::APFloat::IEEEdouble()) {215    const double Value = FloatValue.convertToDouble();216    return llvm::binary_search(IgnoredDoublePointValues, Value);217  }218 219  return false;220}221 222bool MagicNumbersCheck::isSyntheticValue(const SourceManager *SourceManager,223                                         const IntegerLiteral *Literal) const {224  const std::pair<FileID, unsigned> FileOffset =225      SourceManager->getDecomposedLoc(Literal->getLocation());226  if (FileOffset.first.isInvalid())227    return false;228 229  const StringRef BufferIdentifier =230      SourceManager->getBufferOrFake(FileOffset.first).getBufferIdentifier();231 232  return BufferIdentifier.empty();233}234 235bool MagicNumbersCheck::isBitFieldWidth(236    const clang::ast_matchers::MatchFinder::MatchResult &Result,237    const IntegerLiteral &Literal) const {238  return IgnoreBitFieldsWidths &&239         llvm::any_of(Result.Context->getParents(Literal),240                      [&Result](const DynTypedNode &Parent) {241                        return isUsedToDefineABitField(Result, Parent);242                      });243}244 245bool MagicNumbersCheck::isUserDefinedLiteral(246    const clang::ast_matchers::MatchFinder::MatchResult &Result,247    const clang::Expr &Literal) const {248  const DynTypedNodeList Parents = Result.Context->getParents(Literal);249  if (Parents.empty())250    return false;251  return Parents[0].get<UserDefinedLiteral>() != nullptr;252}253 254} // namespace tidy::readability255} // namespace clang256