IssueHash.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. //===---------- IssueHash.cpp - Generate identification hashes --*- C++ -*-===//
  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. #include "clang/StaticAnalyzer/Core/IssueHash.h"
  10. #include "clang/AST/ASTContext.h"
  11. #include "clang/AST/Decl.h"
  12. #include "clang/AST/DeclCXX.h"
  13. #include "clang/Basic/SourceManager.h"
  14. #include "clang/Basic/Specifiers.h"
  15. #include "clang/Lex/Lexer.h"
  16. #include "llvm/ADT/SmallVector.h"
  17. #include "llvm/ADT/StringExtras.h"
  18. #include "llvm/ADT/StringRef.h"
  19. #include "llvm/ADT/Twine.h"
  20. #include "llvm/Support/LineIterator.h"
  21. #include "llvm/Support/MD5.h"
  22. #include "llvm/Support/Path.h"
  23. #include <functional>
  24. #include <sstream>
  25. #include <string>
  26. using namespace clang;
  27. // Get a string representation of the parts of the signature that can be
  28. // overloaded on.
  29. static std::string GetSignature(const FunctionDecl *Target) {
  30. if (!Target)
  31. return "";
  32. std::string Signature;
  33. if (!isa<CXXConstructorDecl>(Target) && !isa<CXXDestructorDecl>(Target) &&
  34. !isa<CXXConversionDecl>(Target))
  35. Signature.append(Target->getReturnType().getAsString()).append(" ");
  36. Signature.append(Target->getQualifiedNameAsString()).append("(");
  37. for (int i = 0, paramsCount = Target->getNumParams(); i < paramsCount; ++i) {
  38. if (i)
  39. Signature.append(", ");
  40. Signature.append(Target->getParamDecl(i)->getType().getAsString());
  41. }
  42. if (Target->isVariadic())
  43. Signature.append(", ...");
  44. Signature.append(")");
  45. const auto *TargetT =
  46. llvm::dyn_cast_or_null<FunctionType>(Target->getType().getTypePtr());
  47. if (!TargetT || !isa<CXXMethodDecl>(Target))
  48. return Signature;
  49. if (TargetT->isConst())
  50. Signature.append(" const");
  51. if (TargetT->isVolatile())
  52. Signature.append(" volatile");
  53. if (TargetT->isRestrict())
  54. Signature.append(" restrict");
  55. if (const auto *TargetPT =
  56. dyn_cast_or_null<FunctionProtoType>(Target->getType().getTypePtr())) {
  57. switch (TargetPT->getRefQualifier()) {
  58. case RQ_LValue:
  59. Signature.append(" &");
  60. break;
  61. case RQ_RValue:
  62. Signature.append(" &&");
  63. break;
  64. default:
  65. break;
  66. }
  67. }
  68. return Signature;
  69. }
  70. static std::string GetEnclosingDeclContextSignature(const Decl *D) {
  71. if (!D)
  72. return "";
  73. if (const auto *ND = dyn_cast<NamedDecl>(D)) {
  74. std::string DeclName;
  75. switch (ND->getKind()) {
  76. case Decl::Namespace:
  77. case Decl::Record:
  78. case Decl::CXXRecord:
  79. case Decl::Enum:
  80. DeclName = ND->getQualifiedNameAsString();
  81. break;
  82. case Decl::CXXConstructor:
  83. case Decl::CXXDestructor:
  84. case Decl::CXXConversion:
  85. case Decl::CXXMethod:
  86. case Decl::Function:
  87. DeclName = GetSignature(dyn_cast_or_null<FunctionDecl>(ND));
  88. break;
  89. case Decl::ObjCMethod:
  90. // ObjC Methods can not be overloaded, qualified name uniquely identifies
  91. // the method.
  92. DeclName = ND->getQualifiedNameAsString();
  93. break;
  94. default:
  95. break;
  96. }
  97. return DeclName;
  98. }
  99. return "";
  100. }
  101. static StringRef GetNthLineOfFile(llvm::MemoryBuffer *Buffer, int Line) {
  102. if (!Buffer)
  103. return "";
  104. llvm::line_iterator LI(*Buffer, false);
  105. for (; !LI.is_at_eof() && LI.line_number() != Line; ++LI)
  106. ;
  107. return *LI;
  108. }
  109. static std::string NormalizeLine(const SourceManager &SM, FullSourceLoc &L,
  110. const LangOptions &LangOpts) {
  111. static StringRef Whitespaces = " \t\n";
  112. StringRef Str = GetNthLineOfFile(SM.getBuffer(L.getFileID(), L),
  113. L.getExpansionLineNumber());
  114. unsigned col = Str.find_first_not_of(Whitespaces);
  115. col++;
  116. SourceLocation StartOfLine =
  117. SM.translateLineCol(SM.getFileID(L), L.getExpansionLineNumber(), col);
  118. llvm::MemoryBuffer *Buffer =
  119. SM.getBuffer(SM.getFileID(StartOfLine), StartOfLine);
  120. if (!Buffer)
  121. return {};
  122. const char *BufferPos = SM.getCharacterData(StartOfLine);
  123. Token Token;
  124. Lexer Lexer(SM.getLocForStartOfFile(SM.getFileID(StartOfLine)), LangOpts,
  125. Buffer->getBufferStart(), BufferPos, Buffer->getBufferEnd());
  126. size_t NextStart = 0;
  127. std::ostringstream LineBuff;
  128. while (!Lexer.LexFromRawLexer(Token) && NextStart < 2) {
  129. if (Token.isAtStartOfLine() && NextStart++ > 0)
  130. continue;
  131. LineBuff << std::string(SM.getCharacterData(Token.getLocation()),
  132. Token.getLength());
  133. }
  134. return LineBuff.str();
  135. }
  136. static llvm::SmallString<32> GetHashOfContent(StringRef Content) {
  137. llvm::MD5 Hash;
  138. llvm::MD5::MD5Result MD5Res;
  139. SmallString<32> Res;
  140. Hash.update(Content);
  141. Hash.final(MD5Res);
  142. llvm::MD5::stringifyResult(MD5Res, Res);
  143. return Res;
  144. }
  145. std::string clang::GetIssueString(const SourceManager &SM,
  146. FullSourceLoc &IssueLoc,
  147. StringRef CheckerName, StringRef BugType,
  148. const Decl *D,
  149. const LangOptions &LangOpts) {
  150. static StringRef Delimiter = "$";
  151. return (llvm::Twine(CheckerName) + Delimiter +
  152. GetEnclosingDeclContextSignature(D) + Delimiter +
  153. llvm::utostr(IssueLoc.getExpansionColumnNumber()) + Delimiter +
  154. NormalizeLine(SM, IssueLoc, LangOpts) + Delimiter + BugType)
  155. .str();
  156. }
  157. SmallString<32> clang::GetIssueHash(const SourceManager &SM,
  158. FullSourceLoc &IssueLoc,
  159. StringRef CheckerName, StringRef BugType,
  160. const Decl *D,
  161. const LangOptions &LangOpts) {
  162. return GetHashOfContent(
  163. GetIssueString(SM, IssueLoc, CheckerName, BugType, D, LangOpts));
  164. }