brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.8 KiB · 52bcf1b Raw
181 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 "IntegerTypesCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/ASTMatchers/ASTMatchFinder.h"12#include "clang/ASTMatchers/ASTMatchers.h"13#include "clang/Basic/AttrKinds.h"14#include "clang/Basic/CharInfo.h"15#include "clang/Basic/IdentifierTable.h"16#include "clang/Basic/TargetInfo.h"17#include "clang/Lex/Lexer.h"18 19namespace clang {20 21using namespace ast_matchers;22 23static Token getTokenAtLoc(SourceLocation Loc,24                           const MatchFinder::MatchResult &MatchResult,25                           IdentifierTable &IdentTable) {26  Token Tok;27  if (Lexer::getRawToken(Loc, Tok, *MatchResult.SourceManager,28                         MatchResult.Context->getLangOpts(), false))29    return Tok;30 31  if (Tok.is(tok::raw_identifier)) {32    IdentifierInfo &Info = IdentTable.get(Tok.getRawIdentifier());33    Tok.setIdentifierInfo(&Info);34    Tok.setKind(Info.getTokenID());35  }36  return Tok;37}38 39namespace {40AST_MATCHER(FunctionDecl, isUserDefineLiteral) {41  return Node.getLiteralIdentifier() != nullptr;42}43 44AST_MATCHER(TypeLoc, isValidAndNotInMacro) {45  const SourceLocation Loc = Node.getBeginLoc();46  return Loc.isValid() && !Loc.isMacroID();47}48 49AST_MATCHER(TypeLoc, isBuiltinType) {50  TypeLoc TL = Node;51  if (auto QualLoc = Node.getAs<QualifiedTypeLoc>())52    TL = QualLoc.getUnqualifiedLoc();53 54  const auto BuiltinLoc = TL.getAs<BuiltinTypeLoc>();55  if (!BuiltinLoc)56    return false;57 58  switch (BuiltinLoc.getTypePtr()->getKind()) {59  case BuiltinType::Short:60  case BuiltinType::Long:61  case BuiltinType::LongLong:62  case BuiltinType::UShort:63  case BuiltinType::ULong:64  case BuiltinType::ULongLong:65    return true;66  default:67    return false;68  }69}70 71} // namespace72 73namespace tidy::google::runtime {74 75IntegerTypesCheck::IntegerTypesCheck(StringRef Name, ClangTidyContext *Context)76    : ClangTidyCheck(Name, Context),77      UnsignedTypePrefix(Options.get("UnsignedTypePrefix", "uint")),78      SignedTypePrefix(Options.get("SignedTypePrefix", "int")),79      TypeSuffix(Options.get("TypeSuffix", "")) {}80 81void IntegerTypesCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {82  Options.store(Opts, "UnsignedTypePrefix", UnsignedTypePrefix);83  Options.store(Opts, "SignedTypePrefix", SignedTypePrefix);84  Options.store(Opts, "TypeSuffix", TypeSuffix);85}86 87void IntegerTypesCheck::registerMatchers(MatchFinder *Finder) {88  // Match any integer types, unless they are passed to a printf-based API:89  //90  // https://google.github.io/styleguide/cppguide.html#64-bit_Portability91  // "Where possible, avoid passing arguments of types specified by92  // bitwidth typedefs to printf-based APIs."93  Finder->addMatcher(94      typeLoc(loc(isInteger()), isValidAndNotInMacro(), isBuiltinType(),95              unless(hasAncestor(96                  callExpr(callee(functionDecl(hasAttr(attr::Format)))))),97              unless(hasParent(parmVarDecl(98                  hasAncestor(functionDecl(isUserDefineLiteral()))))))99          .bind("tl"),100      this);101  IdentTable = std::make_unique<IdentifierTable>(getLangOpts());102}103 104void IntegerTypesCheck::check(const MatchFinder::MatchResult &Result) {105  auto TL = *Result.Nodes.getNodeAs<TypeLoc>("tl");106  const SourceLocation Loc = TL.getBeginLoc();107 108  // Look through qualification.109  if (auto QualLoc = TL.getAs<QualifiedTypeLoc>())110    TL = QualLoc.getUnqualifiedLoc();111 112  auto BuiltinLoc = TL.getAs<BuiltinTypeLoc>();113  if (!BuiltinLoc)114    return;115 116  const Token Tok = getTokenAtLoc(Loc, Result, *IdentTable);117  // Ensure the location actually points to one of the builting integral type118  // names we're interested in. Otherwise, we might be getting this match from119  // implicit code (e.g. an implicit assignment operator of a class containing120  // an array of non-POD types).121  if (!Tok.isOneOf(tok::kw_short, tok::kw_long, tok::kw_unsigned,122                   tok::kw_signed))123    return;124 125  bool IsSigned = false;126  unsigned Width = 0;127  const TargetInfo &TargetInfo = Result.Context->getTargetInfo();128 129  // Look for uses of short, long, long long and their unsigned versions.130  switch (BuiltinLoc.getTypePtr()->getKind()) {131  case BuiltinType::Short:132    Width = TargetInfo.getShortWidth();133    IsSigned = true;134    break;135  case BuiltinType::Long:136    Width = TargetInfo.getLongWidth();137    IsSigned = true;138    break;139  case BuiltinType::LongLong:140    Width = TargetInfo.getLongLongWidth();141    IsSigned = true;142    break;143  case BuiltinType::UShort:144    Width = TargetInfo.getShortWidth();145    IsSigned = false;146    break;147  case BuiltinType::ULong:148    Width = TargetInfo.getLongWidth();149    IsSigned = false;150    break;151  case BuiltinType::ULongLong:152    Width = TargetInfo.getLongLongWidth();153    IsSigned = false;154    break;155  default:156    return;157  }158 159  // We allow "unsigned short port" as that's reasonably common and required by160  // the sockets API.161  const StringRef Port = "unsigned short port";162  const char *Data = Result.SourceManager->getCharacterData(Loc);163  if (!std::strncmp(Data, Port.data(), Port.size()) &&164      !isAsciiIdentifierContinue(Data[Port.size()]))165    return;166 167  const std::string Replacement =168      ((IsSigned ? SignedTypePrefix : UnsignedTypePrefix) + Twine(Width) +169       TypeSuffix)170          .str();171 172  // We don't add a fix-it as changing the type can easily break code,173  // e.g. when a function requires a 'long' argument on all platforms.174  // QualTypes are printed with implicit quotes.175  diag(Loc, "consider replacing %0 with '%1'")176      << BuiltinLoc.getType() << Replacement;177}178 179} // namespace tidy::google::runtime180} // namespace clang181