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