Index: include/clang/StaticAnalyzer/Core/BugId.h =================================================================== --- include/clang/StaticAnalyzer/Core/BugId.h +++ include/clang/StaticAnalyzer/Core/BugId.h @@ -0,0 +1,24 @@ +//===---------- BugId.h - Unique bugid utility ------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_CLANG_STATICANALYZER_CORE_BUGID_H +#define LLVM_CLANG_STATICANALYZER_CORE_BUGID_H + +#include "llvm/ADT/SmallString.h" + +namespace clang { +class Decl; +class SourceManager; +class FullSourceLoc; + +llvm::SmallString<32> GetIssueHash(const SourceManager *SM, FullSourceLoc &L, + llvm::StringRef CheckerName, + llvm::StringRef HashField, const Decl *D); +} + +#endif Index: lib/StaticAnalyzer/Core/BugId.cpp =================================================================== --- lib/StaticAnalyzer/Core/BugId.cpp +++ lib/StaticAnalyzer/Core/BugId.cpp @@ -0,0 +1,169 @@ +//===---------- BugId.cpp - Unique bugid utility ------------------*- 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/BugId.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/Lex/Lexer.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/LineIterator.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/MD5.h" +#include "llvm/ADT/Twine.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "clang/AST/ASTContext.h" + +using namespace clang; + +static std::string GetSignature(const FunctionDecl *Target) { + if (!Target) + return ""; + + std::string Signature; + const CXXConstructorDecl *CDecl = dyn_cast(Target); + const CXXDestructorDecl *DDecl = dyn_cast(Target); + const CXXConversionDecl *ConversionDecl = dyn_cast(Target); + + switch (Target->getStorageClass()) { + case SC_Extern: + Signature.append("extern "); + break; + case SC_Static: + Signature.append("static "); + break; + case SC_PrivateExtern: + Signature.append("__private_extern__ "); + break; + default: + break; + } + + if (Target->isInlineSpecified()) + Signature.append("inline "); + if (Target->isVirtualAsWritten()) + Signature.append("virtual "); + if (Target->isModulePrivate()) + Signature.append("__module_private__ "); + if (Target->isConstexpr() && !Target->isExplicitlyDefaulted()) + Signature.append("constexpr "); + if ((CDecl && CDecl->isExplicitSpecified()) || + (ConversionDecl && ConversionDecl->isExplicit())) + Signature.append("explicit "); + + if (!CDecl && !ConversionDecl && !DDecl) + Signature.append(Target->getReturnType().getAsString()).append(" "); + Signature.append(Target->getQualifiedNameAsString()).append("("); + + const FunctionProtoType *TargetPT = + llvm::dyn_cast_or_null(Target->getType().getTypePtr()); + + for (int i = 0, paramsCount = Target->getNumParams(); i < paramsCount; ++i) { + if (i) + Signature.append(", "); + Signature.append(Target->getParamDecl(i)->getType().getAsString()); + } + + if (TargetPT && TargetPT->isVariadic()) + Signature.append(", ..."); + Signature.append(")"); + + if (TargetPT) { + if (TargetPT->isConst()) + Signature.append(" const"); + if (TargetPT->isVolatile()) + Signature.append(" volatile"); + if (TargetPT->isRestrict()) + Signature.append(" restrict"); + + 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 NamedDecl *ND = dyn_cast(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::ObjCMethod: + case Decl::Function: + DeclName = GetSignature(dyn_cast_or_null(ND)); + break; + default: + break; + } + + return DeclName; + } + + return ""; +} + +static std::string 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->str(); +} + +static llvm::SmallString<32> GetHashOfContent(StringRef Content) { + llvm::MD5 Hash; + llvm::MD5::MD5Result MD5Res; + llvm::SmallString<32> Res; + + Hash.update(Content); + Hash.final(MD5Res); + llvm::MD5::stringifyResult(MD5Res, Res); + + return Res; +} + +llvm::SmallString<32> clang::GetIssueHash(const SourceManager *SM, + FullSourceLoc &L, + StringRef CheckerName, + StringRef HashField, const Decl *D) { + static llvm::StringRef Delimiter = "$"; + + return GetHashOfContent( + (llvm::Twine(llvm::sys::path::filename(SM->getFilename(L))) + Delimiter + + CheckerName + Delimiter + GetEnclosingDeclContextSignature(D) + + Delimiter + std::to_string(L.getExpansionColumnNumber()) + Delimiter + + GetNthLineOfFile(SM->getBuffer(L.getFileID(), L), + L.getExpansionLineNumber()) + + Delimiter + HashField.str()).str()); +} Index: lib/StaticAnalyzer/Core/CMakeLists.txt =================================================================== --- lib/StaticAnalyzer/Core/CMakeLists.txt +++ lib/StaticAnalyzer/Core/CMakeLists.txt @@ -6,6 +6,7 @@ AnalyzerOptions.cpp BasicValueFactory.cpp BlockCounter.cpp + BugId.cpp BugReporter.cpp BugReporterVisitors.cpp CallEvent.cpp Index: lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp =================================================================== --- lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/StaticAnalyzer/Core/BugId.h" #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" @@ -236,6 +237,11 @@ if (!BugType.empty()) os << "\n\n"; + PathDiagnosticLocation UPDLoc = D.getUniqueingLoc(); + FullSourceLoc UL(SMgr.getExpansionLoc(UPDLoc.asLocation()), SMgr); + FullSourceLoc L(SMgr.getExpansionLoc(D.getLocation().asLocation()), SMgr); + const Decl *DeclWithIssue = D.getDeclWithIssue(); + StringRef BugCategory = D.getCategory(); if (!BugCategory.empty()) os << "\n\n"; @@ -246,6 +252,10 @@ os << "\n\n"; + os << "\n\n"; + os << "\n\n"; Index: lib/StaticAnalyzer/Core/PlistDiagnostics.cpp =================================================================== --- lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -11,12 +11,13 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" +#include "clang/StaticAnalyzer/Core/BugId.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/PlistSupport.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/Version.h" #include "clang/Lex/Preprocessor.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" #include "llvm/ADT/DenseMap.h" @@ -390,6 +391,14 @@ o << " check_name"; EmitString(o, D->getCheckName()) << '\n'; + o << " bug_id_1"; + PathDiagnosticLocation UPDLoc = D->getUniqueingLoc(); + FullSourceLoc UL(SM->getExpansionLoc(UPDLoc.asLocation()), *SM); + FullSourceLoc L(SM->getExpansionLoc(D->getLocation().asLocation()), *SM); + const Decl *DeclWithIssue = D->getDeclWithIssue(); + EmitString(o, GetIssueHash(SM, UPDLoc.isValid() ? UL : L, D->getCheckName(), + D->getBugType(), DeclWithIssue).str()) << '\n'; + // Output information about the semantic context where // the issue occurred. if (const Decl *DeclWithIssue = D->getDeclWithIssue()) {