clang-tools  3.8.0
StringIntegerAssignmentCheck.cpp
Go to the documentation of this file.
1 //===--- StringIntegerAssignmentCheck.cpp - clang-tidy---------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
14 
15 using namespace clang::ast_matchers;
16 
17 namespace clang {
18 namespace tidy {
19 
20 void StringIntegerAssignmentCheck::registerMatchers(MatchFinder *Finder) {
21  if (!getLangOpts().CPlusPlus)
22  return;
23  Finder->addMatcher(
24  cxxOperatorCallExpr(
25  anyOf(hasOverloadedOperatorName("="),
26  hasOverloadedOperatorName("+=")),
27  callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
28  hasName("::std::basic_string"),
29  hasTemplateArgument(0, refersToType(qualType().bind("type"))))))),
30  hasArgument(1,
31  ignoringImpCasts(expr(hasType(isInteger()),
32  unless(hasType(isAnyCharacter())))
33  .bind("expr"))),
34  unless(isInTemplateInstantiation())),
35  this);
36 }
37 
38 void StringIntegerAssignmentCheck::check(
39  const MatchFinder::MatchResult &Result) {
40  const auto *Argument = Result.Nodes.getNodeAs<Expr>("expr");
41  SourceLocation Loc = Argument->getLocStart();
42 
43  auto Diag =
44  diag(Loc, "an integer is interpreted as a character code when assigning "
45  "it to a string; if this is intended, cast the integer to the "
46  "appropriate character type; if you want a string "
47  "representation, use the appropriate conversion facility");
48 
49  if (Loc.isMacroID())
50  return;
51 
52  auto CharType = *Result.Nodes.getNodeAs<QualType>("type");
53  bool IsWideCharType = CharType->isWideCharType();
54  if (!CharType->isCharType() && !IsWideCharType)
55  return;
56  bool IsOneDigit = false;
57  bool IsLiteral = false;
58  if (const auto *Literal = dyn_cast<IntegerLiteral>(Argument)) {
59  IsOneDigit = Literal->getValue().getLimitedValue() < 10;
60  IsLiteral = true;
61  }
62 
63  SourceLocation EndLoc = Lexer::getLocForEndOfToken(
64  Argument->getLocEnd(), 0, *Result.SourceManager,
65  Result.Context->getLangOpts());
66  if (IsOneDigit) {
67  Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "L'" : "'")
68  << FixItHint::CreateInsertion(EndLoc, "'");
69  return;
70  }
71  if (IsLiteral) {
72  Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "L\"" : "\"")
73  << FixItHint::CreateInsertion(EndLoc, "\"");
74  return;
75  }
76 
77  if (getLangOpts().CPlusPlus11) {
78  Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "std::to_wstring("
79  : "std::to_string(")
80  << FixItHint::CreateInsertion(EndLoc, ")");
81  }
82 }
83 
84 } // namespace tidy
85 } // namespace clang
SourceLocation Loc
'#' location in the include directive
This class represents one callback function argument by name and value.
std::unique_ptr< ast_matchers::MatchFinder > Finder
Definition: ClangTidy.cpp:188
const NamedDecl * Result
Definition: USRFinder.cpp:121