1 //===--- StringIntegerAssignmentCheck.cpp - clang-tidy---------------------===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "StringIntegerAssignmentCheck.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 #include "clang/Lex/Lexer.h" 13 14 using namespace clang::ast_matchers; 15 16 namespace clang { 17 namespace tidy { 18 namespace bugprone { 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->getBeginLoc(); 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->getEndLoc(), 0, *Result.SourceManager, getLangOpts()); 65 if (IsOneDigit) { 66 Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "L'" : "'") 67 << FixItHint::CreateInsertion(EndLoc, "'"); 68 return; 69 } 70 if (IsLiteral) { 71 Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "L\"" : "\"") 72 << FixItHint::CreateInsertion(EndLoc, "\""); 73 return; 74 } 75 76 if (getLangOpts().CPlusPlus11) { 77 Diag << FixItHint::CreateInsertion(Loc, IsWideCharType ? "std::to_wstring(" 78 : "std::to_string(") 79 << FixItHint::CreateInsertion(EndLoc, ")"); 80 } 81 } 82 83 } // namespace bugprone 84 } // namespace tidy 85 } // namespace clang 86