123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- //===---------- IssueHash.cpp - Generate identification hashes --*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "clang/Analysis/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/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;
- // When a flow sensitive bug happens in templated code we should not generate
- // distinct hash value for every instantiation. Use the signature from the
- // primary template.
- if (const FunctionDecl *InstantiatedFrom =
- Target->getTemplateInstantiationPattern())
- Target = InstantiatedFrom;
- 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::Optional<llvm::MemoryBufferRef> 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, const FullSourceLoc &L,
- const LangOptions &LangOpts) {
- static StringRef Whitespaces = " \t\n";
- StringRef Str = GetNthLineOfFile(SM.getBufferOrNone(L.getFileID(), L),
- L.getExpansionLineNumber());
- StringRef::size_type col = Str.find_first_not_of(Whitespaces);
- if (col == StringRef::npos)
- col = 1; // The line only contains whitespace.
- else
- col++;
- SourceLocation StartOfLine =
- SM.translateLineCol(SM.getFileID(L), L.getExpansionLineNumber(), col);
- Optional<llvm::MemoryBufferRef> Buffer =
- SM.getBufferOrNone(SM.getFileID(StartOfLine), StartOfLine);
- if (!Buffer)
- return {};
- const char *BufferPos = SM.getCharacterData(StartOfLine);
- Token Token;
- Lexer Lexer(SM.getLocForStartOfFile(SM.getFileID(StartOfLine)), LangOpts,
- 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> GetMD5HashOfContent(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 FullSourceLoc &IssueLoc,
- StringRef CheckerName,
- StringRef WarningMessage,
- const Decl *IssueDecl,
- const LangOptions &LangOpts) {
- static StringRef Delimiter = "$";
- return (llvm::Twine(CheckerName) + Delimiter +
- GetEnclosingDeclContextSignature(IssueDecl) + Delimiter +
- Twine(IssueLoc.getExpansionColumnNumber()) + Delimiter +
- NormalizeLine(IssueLoc.getManager(), IssueLoc, LangOpts) +
- Delimiter + WarningMessage)
- .str();
- }
- SmallString<32> clang::getIssueHash(const FullSourceLoc &IssueLoc,
- StringRef CheckerName,
- StringRef WarningMessage,
- const Decl *IssueDecl,
- const LangOptions &LangOpts) {
- return GetMD5HashOfContent(getIssueString(
- IssueLoc, CheckerName, WarningMessage, IssueDecl, LangOpts));
- }
|