babati updated this revision to Diff 30808.
babati added a comment.

Added line normalization.
Updated to the trunk.


http://reviews.llvm.org/D10305

Files:
  include/clang/StaticAnalyzer/Core/BugId.h
  lib/StaticAnalyzer/Core/BugId.cpp
  lib/StaticAnalyzer/Core/CMakeLists.txt
  lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
  lib/StaticAnalyzer/Core/PlistDiagnostics.cpp

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"
@@ -210,7 +211,7 @@
                        unsigned depth) {
   
   IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnter =
-    P.getCallEnterEvent();  
+    P.getCallEnterEvent(); 
 
   if (callEnter)
     ReportPiece(o, *callEnter, FM, SM, LangOpts, indent, depth, true,
@@ -224,7 +225,7 @@
   if (callEnterWithinCaller)
     ReportPiece(o, *callEnterWithinCaller, FM, SM, LangOpts,
                 indent, depth, true);
-  
+
   for (PathPieces::const_iterator I = P.path.begin(), E = P.path.end();I!=E;++I)
     ReportPiece(o, **I, FM, SM, LangOpts, indent, depth, true);
 
@@ -296,8 +297,8 @@
 
   if (!Diags.empty())
     SM = &(*(*Diags.begin())->path.begin())->getLocation().getManager();
-
   
+
   for (std::vector<const PathDiagnostic*>::iterator DI = Diags.begin(),
        DE = Diags.end(); DI != DE; ++DI) {
 
@@ -390,6 +391,14 @@
     o << "   <key>check_name</key>";
     EmitString(o, D->getCheckName()) << '\n';
  
+    o << "   <key>bug_id_1</key>";
+    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()) {
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<!-- BUGTYPE " << BugType << " -->\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<!-- BUGCATEGORY " << BugCategory << " -->\n";
@@ -246,6 +252,10 @@
 
     os  << "\n<!-- FUNCTIONNAME " <<  declName << " -->\n";
 
+    os  << "\n<!-- BUGID1 " <<
+        GetIssueHash(&SMgr, UPDLoc.isValid() ? UL : L, D.getCheckName(), D.getBugType(), DeclWithIssue).str()
+        << " -->\n";
+
     os << "\n<!-- BUGLINE "
        << LineNumber
        << " -->\n";
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/BugId.cpp
===================================================================
--- lib/StaticAnalyzer/Core/BugId.cpp
+++ lib/StaticAnalyzer/Core/BugId.cpp
@@ -0,0 +1,202 @@
+//===---------- 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"
+
+#include <string>
+#include <sstream> 
+#include <functional>
+
+using namespace clang;
+
+static std::string GetSignature(const FunctionDecl *Target) {
+  if (!Target)
+    return "";
+
+  std::string Signature;
+  const CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(Target);
+  const CXXDestructorDecl *DDecl = dyn_cast<CXXDestructorDecl>(Target);
+  const CXXConversionDecl *ConversionDecl = dyn_cast<CXXConversionDecl>(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<FunctionProtoType>(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<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::ObjCMethod:
+    case Decl::Function:
+      DeclName = GetSignature(dyn_cast_or_null<FunctionDecl>(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 std::string NormalizeLine(const SourceManager *SM, FullSourceLoc &L,
+                                 const Decl *D) {
+  static const std::string whitespaces = " \t\n";
+  
+  const LangOptions &Opts = D->getASTContext().getLangOpts();
+  std::string 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.is(clang::tok::TokenKind::comment)) continue;
+    if (Token.isAtStartOfLine() && nextStart++ > 0) continue;
+    lineBuff << std::string(SM->getCharacterData(Token.getLocation()), Token.getLength()); 
+  }
+  // llvm::errs() << "Line: " << lineBuff.str() << "\n"; 
+
+  return lineBuff.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 +
+       NormalizeLine(SM, L, D) + 
+       // GetNthLineOfFile(SM->getBuffer(L.getFileID(), L), L.getExpansionLineNumber()) +
+       Delimiter + HashField.str()).str());
+}
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
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to