195 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			195 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===---------- IssueHash.cpp - Generate identification hashes --*- C++ -*-===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| #include "clang/StaticAnalyzer/Core/IssueHash.h"
 | |
| #include "clang/AST/ASTContext.h"
 | |
| #include "clang/AST/Decl.h"
 | |
| #include "clang/AST/DeclCXX.h"
 | |
| #include "clang/Basic/SourceManager.h"
 | |
| #include "clang/Basic/Specifiers.h"
 | |
| #include "clang/Lex/Lexer.h"
 | |
| #include "llvm/ADT/SmallVector.h"
 | |
| #include "llvm/ADT/StringExtras.h"
 | |
| #include "llvm/ADT/StringRef.h"
 | |
| #include "llvm/ADT/Twine.h"
 | |
| #include "llvm/Support/LineIterator.h"
 | |
| #include "llvm/Support/MD5.h"
 | |
| #include "llvm/Support/Path.h"
 | |
| 
 | |
| #include <functional>
 | |
| #include <sstream>
 | |
| #include <string>
 | |
| 
 | |
| using namespace clang;
 | |
| 
 | |
| // Get a string representation of the parts of the signature that can be 
 | |
| // overloaded on.
 | |
| static std::string GetSignature(const FunctionDecl *Target) {
 | |
|   if (!Target)
 | |
|     return "";
 | |
|   std::string Signature;
 | |
| 
 | |
|   if (!isa<CXXConstructorDecl>(Target) && !isa<CXXDestructorDecl>(Target) &&
 | |
|       !isa<CXXConversionDecl>(Target))
 | |
|     Signature.append(Target->getReturnType().getAsString()).append(" ");
 | |
|   Signature.append(Target->getQualifiedNameAsString()).append("(");
 | |
| 
 | |
|   for (int i = 0, paramsCount = Target->getNumParams(); i < paramsCount; ++i) {
 | |
|     if (i)
 | |
|       Signature.append(", ");
 | |
|     Signature.append(Target->getParamDecl(i)->getType().getAsString());
 | |
|   }
 | |
| 
 | |
|   if (Target->isVariadic())
 | |
|     Signature.append(", ...");
 | |
|   Signature.append(")");
 | |
| 
 | |
|   const auto *TargetT =
 | |
|       llvm::dyn_cast_or_null<FunctionType>(Target->getType().getTypePtr());
 | |
| 
 | |
|   if (!TargetT || !isa<CXXMethodDecl>(Target))
 | |
|     return Signature;
 | |
| 
 | |
|   if (TargetT->isConst())
 | |
|     Signature.append(" const");
 | |
|   if (TargetT->isVolatile())
 | |
|     Signature.append(" volatile");
 | |
|   if (TargetT->isRestrict())
 | |
|     Signature.append(" restrict");
 | |
| 
 | |
|   if (const auto *TargetPT =
 | |
|           dyn_cast_or_null<FunctionProtoType>(Target->getType().getTypePtr())) {
 | |
|     switch (TargetPT->getRefQualifier()) {
 | |
|     case RQ_LValue:
 | |
|       Signature.append(" &");
 | |
|       break;
 | |
|     case RQ_RValue:
 | |
|       Signature.append(" &&");
 | |
|       break;
 | |
|     default:
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Signature;
 | |
| }
 | |
| 
 | |
| static std::string GetEnclosingDeclContextSignature(const Decl *D) {
 | |
|   if (!D)
 | |
|     return "";
 | |
| 
 | |
|   if (const auto *ND = dyn_cast<NamedDecl>(D)) {
 | |
|     std::string DeclName;
 | |
| 
 | |
|     switch (ND->getKind()) {
 | |
|     case Decl::Namespace:
 | |
|     case Decl::Record:
 | |
|     case Decl::CXXRecord:
 | |
|     case Decl::Enum:
 | |
|       DeclName = ND->getQualifiedNameAsString();
 | |
|       break;
 | |
|     case Decl::CXXConstructor:
 | |
|     case Decl::CXXDestructor:
 | |
|     case Decl::CXXConversion:
 | |
|     case Decl::CXXMethod:
 | |
|     case Decl::Function:
 | |
|       DeclName = GetSignature(dyn_cast_or_null<FunctionDecl>(ND));
 | |
|       break;
 | |
|     case Decl::ObjCMethod:
 | |
|       // ObjC Methods can not be overloaded, qualified name uniquely identifies
 | |
|       // the method.
 | |
|       DeclName = ND->getQualifiedNameAsString();
 | |
|       break;
 | |
|     default:
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     return DeclName;
 | |
|   }
 | |
| 
 | |
|   return "";
 | |
| }
 | |
| 
 | |
| static StringRef GetNthLineOfFile(llvm::MemoryBuffer *Buffer, int Line) {
 | |
|   if (!Buffer)
 | |
|     return "";
 | |
| 
 | |
|   llvm::line_iterator LI(*Buffer, false);
 | |
|   for (; !LI.is_at_eof() && LI.line_number() != Line; ++LI)
 | |
|     ;
 | |
| 
 | |
|   return *LI;
 | |
| }
 | |
| 
 | |
| static std::string NormalizeLine(const SourceManager &SM, FullSourceLoc &L,
 | |
|                                  const Decl *D) {
 | |
|   static StringRef Whitespaces = " \t\n";
 | |
| 
 | |
|   const LangOptions &Opts = D->getASTContext().getLangOpts();
 | |
|   StringRef Str = GetNthLineOfFile(SM.getBuffer(L.getFileID(), L),
 | |
|                                    L.getExpansionLineNumber());
 | |
|   unsigned col = Str.find_first_not_of(Whitespaces);
 | |
| 
 | |
|   SourceLocation StartOfLine =
 | |
|       SM.translateLineCol(SM.getFileID(L), L.getExpansionLineNumber(), col);
 | |
|   llvm::MemoryBuffer *Buffer =
 | |
|       SM.getBuffer(SM.getFileID(StartOfLine), StartOfLine);
 | |
|   if (!Buffer)
 | |
|     return {};
 | |
| 
 | |
|   const char *BufferPos = SM.getCharacterData(StartOfLine);
 | |
| 
 | |
|   Token Token;
 | |
|   Lexer Lexer(SM.getLocForStartOfFile(SM.getFileID(StartOfLine)), Opts,
 | |
|               Buffer->getBufferStart(), BufferPos, Buffer->getBufferEnd());
 | |
| 
 | |
|   size_t NextStart = 0;
 | |
|   std::ostringstream LineBuff;
 | |
|   while (!Lexer.LexFromRawLexer(Token) && NextStart < 2) {
 | |
|     if (Token.isAtStartOfLine() && NextStart++ > 0)
 | |
|       continue;
 | |
|     LineBuff << std::string(SM.getCharacterData(Token.getLocation()),
 | |
|                             Token.getLength());
 | |
|   }
 | |
| 
 | |
|   return LineBuff.str();
 | |
| }
 | |
| 
 | |
| static llvm::SmallString<32> GetHashOfContent(StringRef Content) {
 | |
|   llvm::MD5 Hash;
 | |
|   llvm::MD5::MD5Result MD5Res;
 | |
|   SmallString<32> Res;
 | |
| 
 | |
|   Hash.update(Content);
 | |
|   Hash.final(MD5Res);
 | |
|   llvm::MD5::stringifyResult(MD5Res, Res);
 | |
| 
 | |
|   return Res;
 | |
| }
 | |
| 
 | |
| std::string clang::GetIssueString(const SourceManager &SM,
 | |
|                                   FullSourceLoc &IssueLoc,
 | |
|                                   StringRef CheckerName, StringRef BugType,
 | |
|                                   const Decl *D) {
 | |
|   static StringRef Delimiter = "$";
 | |
| 
 | |
|   return (llvm::Twine(CheckerName) + Delimiter +
 | |
|           GetEnclosingDeclContextSignature(D) + Delimiter +
 | |
|           llvm::utostr(IssueLoc.getExpansionColumnNumber()) + Delimiter +
 | |
|           NormalizeLine(SM, IssueLoc, D) + Delimiter + BugType)
 | |
|       .str();
 | |
| }
 | |
| 
 | |
| SmallString<32> clang::GetIssueHash(const SourceManager &SM,
 | |
|                                     FullSourceLoc &IssueLoc,
 | |
|                                     StringRef CheckerName, StringRef BugType,
 | |
|                                     const Decl *D) {
 | |
|   return GetHashOfContent(
 | |
|       GetIssueString(SM, IssueLoc, CheckerName, BugType, D));
 | |
| }
 |