Mercurial > hg > CbC > CbC_llvm
view clang-tools-extra/clang-tidy/readability/MagicNumbersCheck.cpp @ 266:00f31e85ec16 default tip
Added tag current for changeset 31d058e83c98
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Sat, 14 Oct 2023 10:13:55 +0900 |
parents | 1f2b6ac9f198 |
children |
line wrap: on
line source
//===--- MagicNumbersCheck.cpp - clang-tidy-------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // A checker for magic numbers: integer or floating point literals embedded // in the code, outside the definition of a constant or an enumeration. // //===----------------------------------------------------------------------===// #include "MagicNumbersCheck.h" #include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Type.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "llvm/ADT/STLExtras.h" #include <algorithm> using namespace clang::ast_matchers; namespace clang { static bool isUsedToInitializeAConstant(const MatchFinder::MatchResult &Result, const DynTypedNode &Node) { const auto *AsDecl = Node.get<DeclaratorDecl>(); if (AsDecl) { if (AsDecl->getType().isConstQualified()) return true; return AsDecl->isImplicit(); } if (Node.get<EnumConstantDecl>()) return true; return llvm::any_of(Result.Context->getParents(Node), [&Result](const DynTypedNode &Parent) { return isUsedToInitializeAConstant(Result, Parent); }); } static bool isUsedToDefineATypeAlias(const MatchFinder::MatchResult &Result, const DynTypedNode &Node) { if (Node.get<TypeAliasDecl>() || Node.get<TypedefNameDecl>()) return true; return llvm::any_of(Result.Context->getParents(Node), [&Result](const DynTypedNode &Parent) { return isUsedToDefineATypeAlias(Result, Parent); }); } static bool isUsedToDefineABitField(const MatchFinder::MatchResult &Result, const DynTypedNode &Node) { const auto *AsFieldDecl = Node.get<FieldDecl>(); if (AsFieldDecl && AsFieldDecl->isBitField()) return true; return llvm::any_of(Result.Context->getParents(Node), [&Result](const DynTypedNode &Parent) { return isUsedToDefineABitField(Result, Parent); }); } namespace tidy::readability { const char DefaultIgnoredIntegerValues[] = "1;2;3;4;"; const char DefaultIgnoredFloatingPointValues[] = "1.0;100.0;"; MagicNumbersCheck::MagicNumbersCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), IgnoreAllFloatingPointValues( Options.get("IgnoreAllFloatingPointValues", false)), IgnoreBitFieldsWidths(Options.get("IgnoreBitFieldsWidths", true)), IgnorePowersOf2IntegerValues( Options.get("IgnorePowersOf2IntegerValues", false)), IgnoreTypeAliases(Options.get("IgnoreTypeAliases", false)), IgnoreUserDefinedLiterals( Options.get("IgnoreUserDefinedLiterals", false)), RawIgnoredIntegerValues( Options.get("IgnoredIntegerValues", DefaultIgnoredIntegerValues)), RawIgnoredFloatingPointValues(Options.get( "IgnoredFloatingPointValues", DefaultIgnoredFloatingPointValues)) { // Process the set of ignored integer values. const std::vector<StringRef> IgnoredIntegerValuesInput = utils::options::parseStringList(RawIgnoredIntegerValues); IgnoredIntegerValues.resize(IgnoredIntegerValuesInput.size()); llvm::transform(IgnoredIntegerValuesInput, IgnoredIntegerValues.begin(), [](StringRef Value) { int64_t Res; Value.getAsInteger(10, Res); return Res; }); llvm::sort(IgnoredIntegerValues); if (!IgnoreAllFloatingPointValues) { // Process the set of ignored floating point values. const std::vector<StringRef> IgnoredFloatingPointValuesInput = utils::options::parseStringList(RawIgnoredFloatingPointValues); IgnoredFloatingPointValues.reserve(IgnoredFloatingPointValuesInput.size()); IgnoredDoublePointValues.reserve(IgnoredFloatingPointValuesInput.size()); for (const auto &InputValue : IgnoredFloatingPointValuesInput) { llvm::APFloat FloatValue(llvm::APFloat::IEEEsingle()); auto StatusOrErr = FloatValue.convertFromString(InputValue, DefaultRoundingMode); assert(StatusOrErr && "Invalid floating point representation"); consumeError(StatusOrErr.takeError()); IgnoredFloatingPointValues.push_back(FloatValue.convertToFloat()); llvm::APFloat DoubleValue(llvm::APFloat::IEEEdouble()); StatusOrErr = DoubleValue.convertFromString(InputValue, DefaultRoundingMode); assert(StatusOrErr && "Invalid floating point representation"); consumeError(StatusOrErr.takeError()); IgnoredDoublePointValues.push_back(DoubleValue.convertToDouble()); } llvm::sort(IgnoredFloatingPointValues); llvm::sort(IgnoredDoublePointValues); } } void MagicNumbersCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { Options.store(Opts, "IgnoreAllFloatingPointValues", IgnoreAllFloatingPointValues); Options.store(Opts, "IgnoreBitFieldsWidths", IgnoreBitFieldsWidths); Options.store(Opts, "IgnorePowersOf2IntegerValues", IgnorePowersOf2IntegerValues); Options.store(Opts, "IgnoreTypeAliases", IgnoreTypeAliases); Options.store(Opts, "IgnoreUserDefinedLiterals", IgnoreUserDefinedLiterals); Options.store(Opts, "IgnoredIntegerValues", RawIgnoredIntegerValues); Options.store(Opts, "IgnoredFloatingPointValues", RawIgnoredFloatingPointValues); } void MagicNumbersCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher(integerLiteral().bind("integer"), this); if (!IgnoreAllFloatingPointValues) Finder->addMatcher(floatLiteral().bind("float"), this); } void MagicNumbersCheck::check(const MatchFinder::MatchResult &Result) { TraversalKindScope RAII(*Result.Context, TK_AsIs); checkBoundMatch<IntegerLiteral>(Result, "integer"); checkBoundMatch<FloatingLiteral>(Result, "float"); } bool MagicNumbersCheck::isConstant(const MatchFinder::MatchResult &Result, const Expr &ExprResult) const { return llvm::any_of( Result.Context->getParents(ExprResult), [this, &Result](const DynTypedNode &Parent) { if (isUsedToInitializeAConstant(Result, Parent)) return true; if (IgnoreTypeAliases && isUsedToDefineATypeAlias(Result, Parent)) return true; // Ignore this instance, because this matches an // expanded class enumeration value. if (Parent.get<CStyleCastExpr>() && llvm::any_of( Result.Context->getParents(Parent), [](const DynTypedNode &GrandParent) { return GrandParent.get<SubstNonTypeTemplateParmExpr>() != nullptr; })) return true; // Ignore this instance, because this match reports the // location where the template is defined, not where it // is instantiated. if (Parent.get<SubstNonTypeTemplateParmExpr>()) return true; // Don't warn on string user defined literals: // std::string s = "Hello World"s; if (const auto *UDL = Parent.get<UserDefinedLiteral>()) if (UDL->getLiteralOperatorKind() == UserDefinedLiteral::LOK_String) return true; return false; }); } bool MagicNumbersCheck::isIgnoredValue(const IntegerLiteral *Literal) const { const llvm::APInt IntValue = Literal->getValue(); const int64_t Value = IntValue.getZExtValue(); if (Value == 0) return true; if (IgnorePowersOf2IntegerValues && IntValue.isPowerOf2()) return true; return std::binary_search(IgnoredIntegerValues.begin(), IgnoredIntegerValues.end(), Value); } bool MagicNumbersCheck::isIgnoredValue(const FloatingLiteral *Literal) const { const llvm::APFloat FloatValue = Literal->getValue(); if (FloatValue.isZero()) return true; if (&FloatValue.getSemantics() == &llvm::APFloat::IEEEsingle()) { const float Value = FloatValue.convertToFloat(); return std::binary_search(IgnoredFloatingPointValues.begin(), IgnoredFloatingPointValues.end(), Value); } if (&FloatValue.getSemantics() == &llvm::APFloat::IEEEdouble()) { const double Value = FloatValue.convertToDouble(); return std::binary_search(IgnoredDoublePointValues.begin(), IgnoredDoublePointValues.end(), Value); } return false; } bool MagicNumbersCheck::isSyntheticValue(const SourceManager *SourceManager, const IntegerLiteral *Literal) const { const std::pair<FileID, unsigned> FileOffset = SourceManager->getDecomposedLoc(Literal->getLocation()); if (FileOffset.first.isInvalid()) return false; const StringRef BufferIdentifier = SourceManager->getBufferOrFake(FileOffset.first).getBufferIdentifier(); return BufferIdentifier.empty(); } bool MagicNumbersCheck::isBitFieldWidth( const clang::ast_matchers::MatchFinder::MatchResult &Result, const IntegerLiteral &Literal) const { return IgnoreBitFieldsWidths && llvm::any_of(Result.Context->getParents(Literal), [&Result](const DynTypedNode &Parent) { return isUsedToDefineABitField(Result, Parent); }); } bool MagicNumbersCheck::isUserDefinedLiteral( const clang::ast_matchers::MatchFinder::MatchResult &Result, const clang::Expr &Literal) const { DynTypedNodeList Parents = Result.Context->getParents(Literal); if (Parents.empty()) return false; return Parents[0].get<UserDefinedLiteral>() != nullptr; } } // namespace tidy::readability } // namespace clang