head 1.1; branch 1.1.1; access; symbols netbsd-11-0-RC5:1.1.1.1 netbsd-11-0-RC4:1.1.1.1 netbsd-11-0-RC3:1.1.1.1 netbsd-11-0-RC2:1.1.1.1 netbsd-11-0-RC1:1.1.1.1 perseant-exfatfs-base-20250801:1.1.1.1 netbsd-11:1.1.1.1.0.10 netbsd-11-base:1.1.1.1 netbsd-10-1-RELEASE:1.1.1.1 perseant-exfatfs-base-20240630:1.1.1.1 perseant-exfatfs:1.1.1.1.0.8 perseant-exfatfs-base:1.1.1.1 netbsd-10-0-RELEASE:1.1.1.1 netbsd-10-0-RC6:1.1.1.1 netbsd-10-0-RC5:1.1.1.1 netbsd-10-0-RC4:1.1.1.1 netbsd-10-0-RC3:1.1.1.1 netbsd-10-0-RC2:1.1.1.1 netbsd-10-0-RC1:1.1.1.1 netbsd-10:1.1.1.1.0.6 netbsd-10-base:1.1.1.1 cjep_sun2x-base1:1.1.1.1 cjep_sun2x:1.1.1.1.0.4 cjep_sun2x-base:1.1.1.1 cjep_staticlib_x:1.1.1.1.0.2 cjep_staticlib_x-base1:1.1.1.1 LLVM-249b40b558955afe5ac2b549edcf2d7f859c8cc9:1.1.1.1 LLVM:1.1.1; locks; strict; comment @// @; 1.1 date 2021.05.30.01.25.31; author joerg; state Exp; branches 1.1.1.1; next ; commitid uhgdinROdC6tU6VC; 1.1.1.1 date 2021.05.30.01.25.31; author joerg; state Exp; branches 1.1.1.1.2.1; next ; commitid uhgdinROdC6tU6VC; 1.1.1.1.2.1 date 2021.05.30.01.25.31; author cjep; state dead; branches; next 1.1.1.1.2.2; commitid eWz9SBW0XqKjJlVC; 1.1.1.1.2.2 date 2021.05.31.22.07.12; author cjep; state Exp; branches; next ; commitid eWz9SBW0XqKjJlVC; desc @@ 1.1 log @Initial revision @ text @//===---------- 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 #include #include 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(Target) && !isa(Target) && !isa(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(Target->getType().getTypePtr()); if (!TargetT || !isa(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(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(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(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 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 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)); } @ 1.1.1.1 log @Import clang 249b40b558955afe5ac2b549edcf2d7f859c8cc9. @ text @@ 1.1.1.1.2.1 log @file IssueHash.cpp was added on branch cjep_staticlib_x on 2021-05-31 22:07:12 +0000 @ text @d1 207 @ 1.1.1.1.2.2 log @sync with head @ text @a0 207 //===---------- 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 #include #include 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(Target) && !isa(Target) && !isa(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(Target->getType().getTypePtr()); if (!TargetT || !isa(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(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(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(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 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 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)); } @