xref: /llvm-project/clang-tools-extra/clang-tidy/bugprone/StringIntegerAssignmentCheck.cpp (revision c09197e0863d2b50439a79869a10ad4c893fb4d1)
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 
10 #include "StringIntegerAssignmentCheck.h"
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 namespace bugprone {
20 
21 void StringIntegerAssignmentCheck::registerMatchers(MatchFinder *Finder) {
22   if (!getLangOpts().CPlusPlus)
23     return;
24   Finder->addMatcher(
25       cxxOperatorCallExpr(
26           anyOf(hasOverloadedOperatorName("="),
27                 hasOverloadedOperatorName("+=")),
28           callee(cxxMethodDecl(ofClass(classTemplateSpecializationDecl(
29               hasName("::std::basic_string"),
30               hasTemplateArgument(0, refersToType(qualType().bind("type"))))))),
31           hasArgument(1,
32                       ignoringImpCasts(expr(hasType(isInteger()),
33                                             unless(hasType(isAnyCharacter())))
34                                            .bind("expr"))),
35           unless(isInTemplateInstantiation())),
36       this);
37 }
38 
39 void StringIntegerAssignmentCheck::check(
40     const MatchFinder::MatchResult &Result) {
41   const auto *Argument = Result.Nodes.getNodeAs<Expr>("expr");
42   SourceLocation Loc = Argument->getBeginLoc();
43 
44   auto Diag =
45       diag(Loc, "an integer is interpreted as a character code when assigning "
46                 "it to a string; if this is intended, cast the integer to the "
47                 "appropriate character type; if you want a string "
48                 "representation, use the appropriate conversion facility");
49 
50   if (Loc.isMacroID())
51     return;
52 
53   auto CharType = *Result.Nodes.getNodeAs<QualType>("type");
54   bool IsWideCharType = CharType->isWideCharType();
55   if (!CharType->isCharType() && !IsWideCharType)
56     return;
57   bool IsOneDigit = false;
58   bool IsLiteral = false;
59   if (const auto *Literal = dyn_cast<IntegerLiteral>(Argument)) {
60     IsOneDigit = Literal->getValue().getLimitedValue() < 10;
61     IsLiteral = true;
62   }
63 
64   SourceLocation EndLoc = Lexer::getLocForEndOfToken(
65       Argument->getEndLoc(), 0, *Result.SourceManager, 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 bugprone
85 } // namespace tidy
86 } // namespace clang
87