
to reflect the new license. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. llvm-svn: 351636
171 lines
6.4 KiB
C++
171 lines
6.4 KiB
C++
//===--- 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/ASTMatchers/ASTMatchFinder.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include <algorithm>
|
|
|
|
using namespace clang::ast_matchers;
|
|
using namespace clang::ast_type_traits;
|
|
|
|
namespace {
|
|
|
|
bool isUsedToInitializeAConstant(const MatchFinder::MatchResult &Result,
|
|
const DynTypedNode &Node) {
|
|
|
|
const auto *AsDecl = Node.get<clang::DeclaratorDecl>();
|
|
if (AsDecl) {
|
|
if (AsDecl->getType().isConstQualified())
|
|
return true;
|
|
|
|
return AsDecl->isImplicit();
|
|
}
|
|
|
|
if (Node.get<clang::EnumConstantDecl>() != nullptr)
|
|
return true;
|
|
|
|
return llvm::any_of(Result.Context->getParents(Node),
|
|
[&Result](const DynTypedNode &Parent) {
|
|
return isUsedToInitializeAConstant(Result, Parent);
|
|
});
|
|
}
|
|
|
|
} // namespace
|
|
|
|
namespace clang {
|
|
namespace tidy {
|
|
namespace 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)),
|
|
IgnorePowersOf2IntegerValues(
|
|
Options.get("IgnorePowersOf2IntegerValues", false)) {
|
|
// Process the set of ignored integer values.
|
|
const std::vector<std::string> IgnoredIntegerValuesInput =
|
|
utils::options::parseStringList(
|
|
Options.get("IgnoredIntegerValues", DefaultIgnoredIntegerValues));
|
|
IgnoredIntegerValues.resize(IgnoredIntegerValuesInput.size());
|
|
llvm::transform(IgnoredIntegerValuesInput, IgnoredIntegerValues.begin(),
|
|
[](const std::string &Value) { return std::stoll(Value); });
|
|
llvm::sort(IgnoredIntegerValues);
|
|
|
|
if (!IgnoreAllFloatingPointValues) {
|
|
// Process the set of ignored floating point values.
|
|
const std::vector<std::string> IgnoredFloatingPointValuesInput =
|
|
utils::options::parseStringList(Options.get(
|
|
"IgnoredFloatingPointValues", DefaultIgnoredFloatingPointValues));
|
|
IgnoredFloatingPointValues.reserve(IgnoredFloatingPointValuesInput.size());
|
|
IgnoredDoublePointValues.reserve(IgnoredFloatingPointValuesInput.size());
|
|
for (const auto &InputValue : IgnoredFloatingPointValuesInput) {
|
|
llvm::APFloat FloatValue(llvm::APFloat::IEEEsingle());
|
|
FloatValue.convertFromString(InputValue, DefaultRoundingMode);
|
|
IgnoredFloatingPointValues.push_back(FloatValue.convertToFloat());
|
|
|
|
llvm::APFloat DoubleValue(llvm::APFloat::IEEEdouble());
|
|
DoubleValue.convertFromString(InputValue, DefaultRoundingMode);
|
|
IgnoredDoublePointValues.push_back(DoubleValue.convertToDouble());
|
|
}
|
|
llvm::sort(IgnoredFloatingPointValues.begin(),
|
|
IgnoredFloatingPointValues.end());
|
|
llvm::sort(IgnoredDoublePointValues.begin(),
|
|
IgnoredDoublePointValues.end());
|
|
}
|
|
}
|
|
|
|
void MagicNumbersCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
|
|
Options.store(Opts, "IgnoredIntegerValues", DefaultIgnoredIntegerValues);
|
|
Options.store(Opts, "IgnoredFloatingPointValues",
|
|
DefaultIgnoredFloatingPointValues);
|
|
}
|
|
|
|
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) {
|
|
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),
|
|
[&Result](const DynTypedNode &Parent) {
|
|
return isUsedToInitializeAConstant(Result, Parent) ||
|
|
// Ignore this instance, because this match reports the location
|
|
// where the template is defined, not where it is instantiated.
|
|
Parent.get<SubstNonTypeTemplateParmExpr>();
|
|
});
|
|
}
|
|
|
|
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->getBuffer(FileOffset.first)->getBufferIdentifier();
|
|
|
|
return BufferIdentifier.empty();
|
|
}
|
|
|
|
} // namespace readability
|
|
} // namespace tidy
|
|
} // namespace clang
|