================ @@ -0,0 +1,183 @@ +//===--- AvoidPlatformSpecificFundamentalTypesCheck.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 +// +//===----------------------------------------------------------------------===// + +#include "AvoidPlatformSpecificFundamentalTypesCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Type.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/TargetInfo.h" + +using namespace clang::ast_matchers; + +namespace { + +AST_MATCHER(clang::QualType, isBuiltinInt) { + const auto *BT = Node->getAs<clang::BuiltinType>(); + if (!BT) + return false; + + // BT->isInteger() would detect char and bool + switch (BT->getKind()) { + case clang::BuiltinType::Short: + case clang::BuiltinType::UShort: + case clang::BuiltinType::Int: + case clang::BuiltinType::UInt: + case clang::BuiltinType::Long: + case clang::BuiltinType::ULong: + case clang::BuiltinType::LongLong: + case clang::BuiltinType::ULongLong: + return true; + default: + return false; + } +} + +AST_MATCHER(clang::QualType, isBuiltinFloat) { + const auto *BT = Node->getAs<clang::BuiltinType>(); + if (!BT) + return false; + + return BT->isFloatingPoint(); +} + +} // namespace + +namespace clang::tidy::portability { + +AvoidPlatformSpecificFundamentalTypesCheck:: + AvoidPlatformSpecificFundamentalTypesCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + WarnOnFloats(Options.get("WarnOnFloats", true)), + WarnOnInts(Options.get("WarnOnInts", true)), + WarnOnChars(Options.get("WarnOnChars", true)), + IncludeInserter(Options.getLocalOrGlobal("IncludeStyle", + utils::IncludeSorter::IS_LLVM), + areDiagsSelfContained()) { + if (!WarnOnFloats && !WarnOnInts && !WarnOnChars) + this->configurationDiag( + "The check 'portability-avoid-platform-specific-fundamental-types' " + "will not perform any analysis because 'WarnOnFloats', 'WarnOnInts' " + "and 'WarnOnChars' are all false."); +} + +void AvoidPlatformSpecificFundamentalTypesCheck::registerPPCallbacks( + const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { + IncludeInserter.registerPreprocessor(PP); +} + +void AvoidPlatformSpecificFundamentalTypesCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "WarnOnFloats", WarnOnFloats); + Options.store(Opts, "WarnOnInts", WarnOnInts); + Options.store(Opts, "WarnOnChars", WarnOnChars); + Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle()); +} + +static std::string getFloatReplacement(const BuiltinType *BT, + ASTContext &Context) { + const TargetInfo &Target = Context.getTargetInfo(); + + auto GetReplacementType = [](unsigned Width) { + switch (Width) { + // This is ambiguous by default since it could be bfloat16 or float16 + case 16U: + return ""; + case 32U: + return "float32_t"; + case 64U: + return "float64_t"; + case 128U: + return "float128_t"; + default: + return ""; + } + }; + + switch (BT->getKind()) { + // Not an ambiguous type + case BuiltinType::BFloat16: + return "bfloat16_t"; + case BuiltinType::Half: + return GetReplacementType(Target.getHalfWidth()); + case BuiltinType::Float: + return GetReplacementType(Target.getFloatWidth()); + case BuiltinType::Double: + return GetReplacementType(Target.getDoubleWidth()); + default: + return ""; + } +} + +void AvoidPlatformSpecificFundamentalTypesCheck::registerMatchers( + MatchFinder *Finder) { + auto PlatformSpecificFundamentalType = qualType(allOf( + builtinType(), anyOf(WarnOnInts ? isBuiltinInt() : unless(anything()), + WarnOnFloats ? isBuiltinFloat() : unless(anything()), + WarnOnChars ? isChar() : unless(anything()), + WarnOnChars ? isWideChar() : unless(anything())))); + + if (!WarnOnInts && !WarnOnFloats && !WarnOnChars) + return; + + Finder->addMatcher(typeLoc(loc(PlatformSpecificFundamentalType)).bind("type"), + this); +} + +void AvoidPlatformSpecificFundamentalTypesCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *TL = Result.Nodes.getNodeAs<TypeLoc>("type"); + if (!TL) + return; + + SourceLocation Loc = TL->getBeginLoc(); + QualType QT = TL->getType(); + SourceRange TypeRange = TL->getSourceRange(); + + // Skip implicit type locations, such as literals + if (!Loc.isValid() || !TypeRange.isValid()) + return; + + const std::string TypeName = QT.getUnqualifiedType().getAsString(); + + const auto *BT = QT->getAs<BuiltinType>(); + + assert(BT); + if (BT->isFloatingPoint()) { + const std::string Replacement = getFloatReplacement(BT, *Result.Context); + if (!Replacement.empty()) { + auto Diag = + diag(Loc, "avoid using platform-dependent floating point type '%0'; " + "consider using '%1' instead") + << TypeName << Replacement; + + if (TypeRange.isValid()) + Diag << FixItHint::CreateReplacement(TypeRange, Replacement); + + if (auto IncludeFixit = IncludeInserter.createIncludeInsertion( + Result.SourceManager->getFileID(Loc), "<stdfloat>")) { + Diag << *IncludeFixit; + } + } else { + diag(Loc, "avoid using platform-dependent floating point type '%0'; " + "consider using a 'typedef' or fixed-width type instead") + << TypeName; + } ---------------- vbvictor wrote:
I think early return will be better here. ```suggestion if (Replacement.empty()) { diag(Loc, "avoid using platform-dependent floating point type '%0'; " "consider using a 'typedef' or fixed-width type instead") << TypeName; return; } auto Diag = diag(Loc, "avoid using platform-dependent floating point type '%0'; " "consider using '%1' instead") << TypeName << Replacement; if (TypeRange.isValid()) Diag << FixItHint::CreateReplacement(TypeRange, Replacement); if (auto IncludeFixit = IncludeInserter.createIncludeInsertion( Result.SourceManager->getFileID(Loc), "<stdfloat>")) { Diag << *IncludeFixit; } ``` https://github.com/llvm/llvm-project/pull/146970 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits