<div dir="ltr">The move of OSLog.h and FormatString.h to AST doesn't look obviously correct.<div>Do these really belong in this layer? I think this patch needs review from someone who knows AST/ better than myself... was there a review?</div><div><br></div><div>(If the do belong here: the namespaces and comments don't seem to have been updated)</div></div><br><div class="gmail_quote"><div dir="ltr">On Fri, Nov 2, 2018 at 2:16 PM Tim Northover via cfe-commits <<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: tnorthover<br>
Date: Fri Nov 2 06:14:11 2018<br>
New Revision: 345971<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=345971&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=345971&view=rev</a><br>
Log:<br>
Reapply Logging: make os_log buffer size an integer constant expression.<br>
<br>
The size of an os_log buffer is known at any stage of compilation, so making it<br>
a constant expression means that the common idiom of declaring a buffer for it<br>
won't result in a VLA. That allows the compiler to skip saving and restoring<br>
the stack pointer around such buffers.<br>
<br>
This also moves the OSLog and other FormatString helpers from<br>
libclangAnalysis to libclangAST to avoid a circular dependency.<br>
<br>
Added:<br>
cfe/trunk/include/clang/AST/FormatString.h<br>
cfe/trunk/include/clang/AST/OSLog.h<br>
cfe/trunk/lib/AST/FormatString.cpp<br>
cfe/trunk/lib/AST/FormatStringParsing.h<br>
cfe/trunk/lib/AST/OSLog.cpp<br>
cfe/trunk/lib/AST/PrintfFormatString.cpp<br>
cfe/trunk/lib/AST/ScanfFormatString.cpp<br>
Removed:<br>
cfe/trunk/include/clang/Analysis/Analyses/FormatString.h<br>
cfe/trunk/include/clang/Analysis/Analyses/OSLog.h<br>
cfe/trunk/lib/Analysis/FormatString.cpp<br>
cfe/trunk/lib/Analysis/FormatStringParsing.h<br>
cfe/trunk/lib/Analysis/OSLog.cpp<br>
cfe/trunk/lib/Analysis/PrintfFormatString.cpp<br>
cfe/trunk/lib/Analysis/ScanfFormatString.cpp<br>
Modified:<br>
cfe/trunk/lib/AST/CMakeLists.txt<br>
cfe/trunk/lib/AST/ExprConstant.cpp<br>
cfe/trunk/lib/Analysis/CMakeLists.txt<br>
cfe/trunk/lib/CodeGen/CGBuiltin.cpp<br>
cfe/trunk/lib/Sema/SemaChecking.cpp<br>
cfe/trunk/test/CodeGen/builtins.c<br>
<br>
Added: cfe/trunk/include/clang/AST/FormatString.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/FormatString.h?rev=345971&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/FormatString.h?rev=345971&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/AST/FormatString.h (added)<br>
+++ cfe/trunk/include/clang/AST/FormatString.h Fri Nov 2 06:14:11 2018<br>
@@ -0,0 +1,719 @@<br>
+//= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+// This file defines APIs for analyzing the format strings of printf, fscanf,<br>
+// and friends.<br>
+//<br>
+// The structure of format strings for fprintf are described in C99 7.19.6.1.<br>
+//<br>
+// The structure of format strings for fscanf are described in C99 7.19.6.2.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H<br>
+#define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H<br>
+<br>
+#include "clang/AST/CanonicalType.h"<br>
+<br>
+namespace clang {<br>
+<br>
+class TargetInfo;<br>
+<br>
+//===----------------------------------------------------------------------===//<br>
+/// Common components of both fprintf and fscanf format strings.<br>
+namespace analyze_format_string {<br>
+<br>
+/// Class representing optional flags with location and representation<br>
+/// information.<br>
+class OptionalFlag {<br>
+public:<br>
+ OptionalFlag(const char *Representation)<br>
+ : representation(Representation), flag(false) {}<br>
+ bool isSet() const { return flag; }<br>
+ void set() { flag = true; }<br>
+ void clear() { flag = false; }<br>
+ void setPosition(const char *position) {<br>
+ assert(position);<br>
+ flag = true;<br>
+ this->position = position;<br>
+ }<br>
+ const char *getPosition() const {<br>
+ assert(position);<br>
+ return position;<br>
+ }<br>
+ const char *toString() const { return representation; }<br>
+<br>
+ // Overloaded operators for bool like qualities<br>
+ explicit operator bool() const { return flag; }<br>
+ OptionalFlag& operator=(const bool &rhs) {<br>
+ flag = rhs;<br>
+ return *this; // Return a reference to myself.<br>
+ }<br>
+private:<br>
+ const char *representation;<br>
+ const char *position;<br>
+ bool flag;<br>
+};<br>
+<br>
+/// Represents the length modifier in a format string in scanf/printf.<br>
+class LengthModifier {<br>
+public:<br>
+ enum Kind {<br>
+ None,<br>
+ AsChar, // 'hh'<br>
+ AsShort, // 'h'<br>
+ AsLong, // 'l'<br>
+ AsLongLong, // 'll'<br>
+ AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types)<br>
+ AsIntMax, // 'j'<br>
+ AsSizeT, // 'z'<br>
+ AsPtrDiff, // 't'<br>
+ AsInt32, // 'I32' (MSVCRT, like __int32)<br>
+ AsInt3264, // 'I' (MSVCRT, like __int3264 from MIDL)<br>
+ AsInt64, // 'I64' (MSVCRT, like __int64)<br>
+ AsLongDouble, // 'L'<br>
+ AsAllocate, // for '%as', GNU extension to C90 scanf<br>
+ AsMAllocate, // for '%ms', GNU extension to scanf<br>
+ AsWide, // 'w' (MSVCRT, like l but only for c, C, s, S, or Z<br>
+ AsWideChar = AsLong // for '%ls', only makes sense for printf<br>
+ };<br>
+<br>
+ LengthModifier()<br>
+ : Position(nullptr), kind(None) {}<br>
+ LengthModifier(const char *pos, Kind k)<br>
+ : Position(pos), kind(k) {}<br>
+<br>
+ const char *getStart() const {<br>
+ return Position;<br>
+ }<br>
+<br>
+ unsigned getLength() const {<br>
+ switch (kind) {<br>
+ default:<br>
+ return 1;<br>
+ case AsLongLong:<br>
+ case AsChar:<br>
+ return 2;<br>
+ case AsInt32:<br>
+ case AsInt64:<br>
+ return 3;<br>
+ case None:<br>
+ return 0;<br>
+ }<br>
+ }<br>
+<br>
+ Kind getKind() const { return kind; }<br>
+ void setKind(Kind k) { kind = k; }<br>
+<br>
+ const char *toString() const;<br>
+<br>
+private:<br>
+ const char *Position;<br>
+ Kind kind;<br>
+};<br>
+<br>
+class ConversionSpecifier {<br>
+public:<br>
+ enum Kind {<br>
+ InvalidSpecifier = 0,<br>
+ // C99 conversion specifiers.<br>
+ cArg,<br>
+ dArg,<br>
+ DArg, // Apple extension<br>
+ iArg,<br>
+ IntArgBeg = dArg,<br>
+ IntArgEnd = iArg,<br>
+<br>
+ oArg,<br>
+ OArg, // Apple extension<br>
+ uArg,<br>
+ UArg, // Apple extension<br>
+ xArg,<br>
+ XArg,<br>
+ UIntArgBeg = oArg,<br>
+ UIntArgEnd = XArg,<br>
+<br>
+ fArg,<br>
+ FArg,<br>
+ eArg,<br>
+ EArg,<br>
+ gArg,<br>
+ GArg,<br>
+ aArg,<br>
+ AArg,<br>
+ DoubleArgBeg = fArg,<br>
+ DoubleArgEnd = AArg,<br>
+<br>
+ sArg,<br>
+ pArg,<br>
+ nArg,<br>
+ PercentArg,<br>
+ CArg,<br>
+ SArg,<br>
+<br>
+ // Apple extension: P specifies to os_log that the data being pointed to is<br>
+ // to be copied by os_log. The precision indicates the number of bytes to<br>
+ // copy.<br>
+ PArg,<br>
+<br>
+ // ** Printf-specific **<br>
+<br>
+ ZArg, // MS extension<br>
+<br>
+ // Objective-C specific specifiers.<br>
+ ObjCObjArg, // '@'<br>
+ ObjCBeg = ObjCObjArg,<br>
+ ObjCEnd = ObjCObjArg,<br>
+<br>
+ // FreeBSD kernel specific specifiers.<br>
+ FreeBSDbArg,<br>
+ FreeBSDDArg,<br>
+ FreeBSDrArg,<br>
+ FreeBSDyArg,<br>
+<br>
+ // GlibC specific specifiers.<br>
+ PrintErrno, // 'm'<br>
+<br>
+ PrintfConvBeg = ObjCObjArg,<br>
+ PrintfConvEnd = PrintErrno,<br>
+<br>
+ // ** Scanf-specific **<br>
+ ScanListArg, // '['<br>
+ ScanfConvBeg = ScanListArg,<br>
+ ScanfConvEnd = ScanListArg<br>
+ };<br>
+<br>
+ ConversionSpecifier(bool isPrintf = true)<br>
+ : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),<br>
+ kind(InvalidSpecifier) {}<br>
+<br>
+ ConversionSpecifier(bool isPrintf, const char *pos, Kind k)<br>
+ : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}<br>
+<br>
+ const char *getStart() const {<br>
+ return Position;<br>
+ }<br>
+<br>
+ StringRef getCharacters() const {<br>
+ return StringRef(getStart(), getLength());<br>
+ }<br>
+<br>
+ bool consumesDataArgument() const {<br>
+ switch (kind) {<br>
+ case PrintErrno:<br>
+ assert(IsPrintf);<br>
+ return false;<br>
+ case PercentArg:<br>
+ return false;<br>
+ case InvalidSpecifier:<br>
+ return false;<br>
+ default:<br>
+ return true;<br>
+ }<br>
+ }<br>
+<br>
+ Kind getKind() const { return kind; }<br>
+ void setKind(Kind k) { kind = k; }<br>
+ unsigned getLength() const {<br>
+ return EndScanList ? EndScanList - Position : 1;<br>
+ }<br>
+ void setEndScanList(const char *pos) { EndScanList = pos; }<br>
+<br>
+ bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||<br>
+ kind == FreeBSDrArg || kind == FreeBSDyArg; }<br>
+ bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }<br>
+ bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }<br>
+ bool isDoubleArg() const {<br>
+ return kind >= DoubleArgBeg && kind <= DoubleArgEnd;<br>
+ }<br>
+<br>
+ const char *toString() const;<br>
+<br>
+ bool isPrintfKind() const { return IsPrintf; }<br>
+<br>
+ Optional<ConversionSpecifier> getStandardSpecifier() const;<br>
+<br>
+protected:<br>
+ bool IsPrintf;<br>
+ const char *Position;<br>
+ const char *EndScanList;<br>
+ Kind kind;<br>
+};<br>
+<br>
+class ArgType {<br>
+public:<br>
+ enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,<br>
+ AnyCharTy, CStrTy, WCStrTy, WIntTy };<br>
+<br>
+ enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic };<br>
+<br>
+private:<br>
+ const Kind K;<br>
+ QualType T;<br>
+ const char *Name = nullptr;<br>
+ bool Ptr = false;<br>
+<br>
+ /// The TypeKind identifies certain well-known types like size_t and<br>
+ /// ptrdiff_t.<br>
+ enum class TypeKind { DontCare, SizeT, PtrdiffT };<br>
+ TypeKind TK = TypeKind::DontCare;<br>
+<br>
+public:<br>
+ ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}<br>
+ ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {}<br>
+ ArgType(CanQualType T) : K(SpecificTy), T(T) {}<br>
+<br>
+ static ArgType Invalid() { return ArgType(InvalidTy); }<br>
+ bool isValid() const { return K != InvalidTy; }<br>
+<br>
+ bool isSizeT() const { return TK == TypeKind::SizeT; }<br>
+<br>
+ bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }<br>
+<br>
+ /// Create an ArgType which corresponds to the type pointer to A.<br>
+ static ArgType PtrTo(const ArgType& A) {<br>
+ assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");<br>
+ ArgType Res = A;<br>
+ Res.Ptr = true;<br>
+ return Res;<br>
+ }<br>
+<br>
+ /// Create an ArgType which corresponds to the size_t/ssize_t type.<br>
+ static ArgType makeSizeT(const ArgType &A) {<br>
+ ArgType Res = A;<br>
+ Res.TK = TypeKind::SizeT;<br>
+ return Res;<br>
+ }<br>
+<br>
+ /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t<br>
+ /// type.<br>
+ static ArgType makePtrdiffT(const ArgType &A) {<br>
+ ArgType Res = A;<br>
+ Res.TK = TypeKind::PtrdiffT;<br>
+ return Res;<br>
+ }<br>
+<br>
+ MatchKind matchesType(ASTContext &C, QualType argTy) const;<br>
+<br>
+ QualType getRepresentativeType(ASTContext &C) const;<br>
+<br>
+ std::string getRepresentativeTypeName(ASTContext &C) const;<br>
+};<br>
+<br>
+class OptionalAmount {<br>
+public:<br>
+ enum HowSpecified { NotSpecified, Constant, Arg, Invalid };<br>
+<br>
+ OptionalAmount(HowSpecified howSpecified,<br>
+ unsigned amount,<br>
+ const char *amountStart,<br>
+ unsigned amountLength,<br>
+ bool usesPositionalArg)<br>
+ : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),<br>
+ UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}<br>
+<br>
+ OptionalAmount(bool valid = true)<br>
+ : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),<br>
+ UsesPositionalArg(0), UsesDotPrefix(0) {}<br>
+<br>
+ bool isInvalid() const {<br>
+ return hs == Invalid;<br>
+ }<br>
+<br>
+ HowSpecified getHowSpecified() const { return hs; }<br>
+ void setHowSpecified(HowSpecified h) { hs = h; }<br>
+<br>
+ bool hasDataArgument() const { return hs == Arg; }<br>
+<br>
+ unsigned getArgIndex() const {<br>
+ assert(hasDataArgument());<br>
+ return amt;<br>
+ }<br>
+<br>
+ unsigned getConstantAmount() const {<br>
+ assert(hs == Constant);<br>
+ return amt;<br>
+ }<br>
+<br>
+ const char *getStart() const {<br>
+ // We include the . character if it is given.<br>
+ return start - UsesDotPrefix;<br>
+ }<br>
+<br>
+ unsigned getConstantLength() const {<br>
+ assert(hs == Constant);<br>
+ return length + UsesDotPrefix;<br>
+ }<br>
+<br>
+ ArgType getArgType(ASTContext &Ctx) const;<br>
+<br>
+ void toString(raw_ostream &os) const;<br>
+<br>
+ bool usesPositionalArg() const { return (bool) UsesPositionalArg; }<br>
+ unsigned getPositionalArgIndex() const {<br>
+ assert(hasDataArgument());<br>
+ return amt + 1;<br>
+ }<br>
+<br>
+ bool usesDotPrefix() const { return UsesDotPrefix; }<br>
+ void setUsesDotPrefix() { UsesDotPrefix = true; }<br>
+<br>
+private:<br>
+ const char *start;<br>
+ unsigned length;<br>
+ HowSpecified hs;<br>
+ unsigned amt;<br>
+ bool UsesPositionalArg : 1;<br>
+ bool UsesDotPrefix;<br>
+};<br>
+<br>
+<br>
+class FormatSpecifier {<br>
+protected:<br>
+ LengthModifier LM;<br>
+ OptionalAmount FieldWidth;<br>
+ ConversionSpecifier CS;<br>
+ /// Positional arguments, an IEEE extension:<br>
+ /// IEEE Std 1003.1, 2004 Edition<br>
+ /// <a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html" rel="noreferrer" target="_blank">http://www.opengroup.org/onlinepubs/009695399/functions/printf.html</a><br>
+ bool UsesPositionalArg;<br>
+ unsigned argIndex;<br>
+public:<br>
+ FormatSpecifier(bool isPrintf)<br>
+ : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {}<br>
+<br>
+ void setLengthModifier(LengthModifier lm) {<br>
+ LM = lm;<br>
+ }<br>
+<br>
+ void setUsesPositionalArg() { UsesPositionalArg = true; }<br>
+<br>
+ void setArgIndex(unsigned i) {<br>
+ argIndex = i;<br>
+ }<br>
+<br>
+ unsigned getArgIndex() const {<br>
+ return argIndex;<br>
+ }<br>
+<br>
+ unsigned getPositionalArgIndex() const {<br>
+ return argIndex + 1;<br>
+ }<br>
+<br>
+ const LengthModifier &getLengthModifier() const {<br>
+ return LM;<br>
+ }<br>
+<br>
+ const OptionalAmount &getFieldWidth() const {<br>
+ return FieldWidth;<br>
+ }<br>
+<br>
+ void setFieldWidth(const OptionalAmount &Amt) {<br>
+ FieldWidth = Amt;<br>
+ }<br>
+<br>
+ bool usesPositionalArg() const { return UsesPositionalArg; }<br>
+<br>
+ bool hasValidLengthModifier(const TargetInfo &Target) const;<br>
+<br>
+ bool hasStandardLengthModifier() const;<br>
+<br>
+ Optional<LengthModifier> getCorrectedLengthModifier() const;<br>
+<br>
+ bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;<br>
+<br>
+ bool hasStandardLengthConversionCombination() const;<br>
+<br>
+ /// For a TypedefType QT, if it is a named integer type such as size_t,<br>
+ /// assign the appropriate value to LM and return true.<br>
+ static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);<br>
+};<br>
+<br>
+} // end analyze_format_string namespace<br>
+<br>
+//===----------------------------------------------------------------------===//<br>
+/// Pieces specific to fprintf format strings.<br>
+<br>
+namespace analyze_printf {<br>
+<br>
+class PrintfConversionSpecifier :<br>
+ public analyze_format_string::ConversionSpecifier {<br>
+public:<br>
+ PrintfConversionSpecifier()<br>
+ : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}<br>
+<br>
+ PrintfConversionSpecifier(const char *pos, Kind k)<br>
+ : ConversionSpecifier(true, pos, k) {}<br>
+<br>
+ bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }<br>
+ bool isDoubleArg() const { return kind >= DoubleArgBeg &&<br>
+ kind <= DoubleArgEnd; }<br>
+<br>
+ static bool classof(const analyze_format_string::ConversionSpecifier *CS) {<br>
+ return CS->isPrintfKind();<br>
+ }<br>
+};<br>
+<br>
+using analyze_format_string::ArgType;<br>
+using analyze_format_string::LengthModifier;<br>
+using analyze_format_string::OptionalAmount;<br>
+using analyze_format_string::OptionalFlag;<br>
+<br>
+class PrintfSpecifier : public analyze_format_string::FormatSpecifier {<br>
+ OptionalFlag HasThousandsGrouping; // ''', POSIX extension.<br>
+ OptionalFlag IsLeftJustified; // '-'<br>
+ OptionalFlag HasPlusPrefix; // '+'<br>
+ OptionalFlag HasSpacePrefix; // ' '<br>
+ OptionalFlag HasAlternativeForm; // '#'<br>
+ OptionalFlag HasLeadingZeroes; // '0'<br>
+ OptionalFlag HasObjCTechnicalTerm; // '[tt]'<br>
+ OptionalFlag IsPrivate; // '{private}'<br>
+ OptionalFlag IsPublic; // '{public}'<br>
+ OptionalAmount Precision;<br>
+public:<br>
+ PrintfSpecifier()<br>
+ : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),<br>
+ IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),<br>
+ HasAlternativeForm("#"), HasLeadingZeroes("0"),<br>
+ HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public") {}<br>
+<br>
+ static PrintfSpecifier Parse(const char *beg, const char *end);<br>
+<br>
+ // Methods for incrementally constructing the PrintfSpecifier.<br>
+ void setConversionSpecifier(const PrintfConversionSpecifier &cs) {<br>
+ CS = cs;<br>
+ }<br>
+ void setHasThousandsGrouping(const char *position) {<br>
+ HasThousandsGrouping.setPosition(position);<br>
+ }<br>
+ void setIsLeftJustified(const char *position) {<br>
+ IsLeftJustified.setPosition(position);<br>
+ }<br>
+ void setHasPlusPrefix(const char *position) {<br>
+ HasPlusPrefix.setPosition(position);<br>
+ }<br>
+ void setHasSpacePrefix(const char *position) {<br>
+ HasSpacePrefix.setPosition(position);<br>
+ }<br>
+ void setHasAlternativeForm(const char *position) {<br>
+ HasAlternativeForm.setPosition(position);<br>
+ }<br>
+ void setHasLeadingZeros(const char *position) {<br>
+ HasLeadingZeroes.setPosition(position);<br>
+ }<br>
+ void setHasObjCTechnicalTerm(const char *position) {<br>
+ HasObjCTechnicalTerm.setPosition(position);<br>
+ }<br>
+ void setIsPrivate(const char *position) { IsPrivate.setPosition(position); }<br>
+ void setIsPublic(const char *position) { IsPublic.setPosition(position); }<br>
+ void setUsesPositionalArg() { UsesPositionalArg = true; }<br>
+<br>
+ // Methods for querying the format specifier.<br>
+<br>
+ const PrintfConversionSpecifier &getConversionSpecifier() const {<br>
+ return cast<PrintfConversionSpecifier>(CS);<br>
+ }<br>
+<br>
+ void setPrecision(const OptionalAmount &Amt) {<br>
+ Precision = Amt;<br>
+ Precision.setUsesDotPrefix();<br>
+ }<br>
+<br>
+ const OptionalAmount &getPrecision() const {<br>
+ return Precision;<br>
+ }<br>
+<br>
+ bool consumesDataArgument() const {<br>
+ return getConversionSpecifier().consumesDataArgument();<br>
+ }<br>
+<br>
+ /// Returns the builtin type that a data argument<br>
+ /// paired with this format specifier should have. This method<br>
+ /// will return null if the format specifier does not have<br>
+ /// a matching data argument or the matching argument matches<br>
+ /// more than one type.<br>
+ ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;<br>
+<br>
+ const OptionalFlag &hasThousandsGrouping() const {<br>
+ return HasThousandsGrouping;<br>
+ }<br>
+ const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }<br>
+ const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }<br>
+ const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }<br>
+ const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }<br>
+ const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }<br>
+ const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; }<br>
+ const OptionalFlag &isPrivate() const { return IsPrivate; }<br>
+ const OptionalFlag &isPublic() const { return IsPublic; }<br>
+ bool usesPositionalArg() const { return UsesPositionalArg; }<br>
+<br>
+ /// Changes the specifier and length according to a QualType, retaining any<br>
+ /// flags or options. Returns true on success, or false when a conversion<br>
+ /// was not successful.<br>
+ bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,<br>
+ bool IsObjCLiteral);<br>
+<br>
+ void toString(raw_ostream &os) const;<br>
+<br>
+ // Validation methods - to check if any element results in undefined behavior<br>
+ bool hasValidPlusPrefix() const;<br>
+ bool hasValidAlternativeForm() const;<br>
+ bool hasValidLeadingZeros() const;<br>
+ bool hasValidSpacePrefix() const;<br>
+ bool hasValidLeftJustified() const;<br>
+ bool hasValidThousandsGroupingPrefix() const;<br>
+<br>
+ bool hasValidPrecision() const;<br>
+ bool hasValidFieldWidth() const;<br>
+};<br>
+} // end analyze_printf namespace<br>
+<br>
+//===----------------------------------------------------------------------===//<br>
+/// Pieces specific to fscanf format strings.<br>
+<br>
+namespace analyze_scanf {<br>
+<br>
+class ScanfConversionSpecifier :<br>
+ public analyze_format_string::ConversionSpecifier {<br>
+public:<br>
+ ScanfConversionSpecifier()<br>
+ : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}<br>
+<br>
+ ScanfConversionSpecifier(const char *pos, Kind k)<br>
+ : ConversionSpecifier(false, pos, k) {}<br>
+<br>
+ static bool classof(const analyze_format_string::ConversionSpecifier *CS) {<br>
+ return !CS->isPrintfKind();<br>
+ }<br>
+};<br>
+<br>
+using analyze_format_string::ArgType;<br>
+using analyze_format_string::LengthModifier;<br>
+using analyze_format_string::OptionalAmount;<br>
+using analyze_format_string::OptionalFlag;<br>
+<br>
+class ScanfSpecifier : public analyze_format_string::FormatSpecifier {<br>
+ OptionalFlag SuppressAssignment; // '*'<br>
+public:<br>
+ ScanfSpecifier() :<br>
+ FormatSpecifier(/* isPrintf = */ false),<br>
+ SuppressAssignment("*") {}<br>
+<br>
+ void setSuppressAssignment(const char *position) {<br>
+ SuppressAssignment.setPosition(position);<br>
+ }<br>
+<br>
+ const OptionalFlag &getSuppressAssignment() const {<br>
+ return SuppressAssignment;<br>
+ }<br>
+<br>
+ void setConversionSpecifier(const ScanfConversionSpecifier &cs) {<br>
+ CS = cs;<br>
+ }<br>
+<br>
+ const ScanfConversionSpecifier &getConversionSpecifier() const {<br>
+ return cast<ScanfConversionSpecifier>(CS);<br>
+ }<br>
+<br>
+ bool consumesDataArgument() const {<br>
+ return CS.consumesDataArgument() && !SuppressAssignment;<br>
+ }<br>
+<br>
+ ArgType getArgType(ASTContext &Ctx) const;<br>
+<br>
+ bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,<br>
+ ASTContext &Ctx);<br>
+<br>
+ void toString(raw_ostream &os) const;<br>
+<br>
+ static ScanfSpecifier Parse(const char *beg, const char *end);<br>
+};<br>
+<br>
+} // end analyze_scanf namespace<br>
+<br>
+//===----------------------------------------------------------------------===//<br>
+// Parsing and processing of format strings (both fprintf and fscanf).<br>
+<br>
+namespace analyze_format_string {<br>
+<br>
+enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };<br>
+<br>
+class FormatStringHandler {<br>
+public:<br>
+ FormatStringHandler() {}<br>
+ virtual ~FormatStringHandler();<br>
+<br>
+ virtual void HandleNullChar(const char *nullCharacter) {}<br>
+<br>
+ virtual void HandlePosition(const char *startPos, unsigned posLen) {}<br>
+<br>
+ virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,<br>
+ PositionContext p) {}<br>
+<br>
+ virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}<br>
+<br>
+ virtual void HandleIncompleteSpecifier(const char *startSpecifier,<br>
+ unsigned specifierLen) {}<br>
+<br>
+ virtual void HandleEmptyObjCModifierFlag(const char *startFlags,<br>
+ unsigned flagsLen) {}<br>
+<br>
+ virtual void HandleInvalidObjCModifierFlag(const char *startFlag,<br>
+ unsigned flagLen) {}<br>
+<br>
+ virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,<br>
+ const char *flagsEnd,<br>
+ const char *conversionPosition) {}<br>
+ // Printf-specific handlers.<br>
+<br>
+ virtual bool HandleInvalidPrintfConversionSpecifier(<br>
+ const analyze_printf::PrintfSpecifier &FS,<br>
+ const char *startSpecifier,<br>
+ unsigned specifierLen) {<br>
+ return true;<br>
+ }<br>
+<br>
+ virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,<br>
+ const char *startSpecifier,<br>
+ unsigned specifierLen) {<br>
+ return true;<br>
+ }<br>
+<br>
+ // Scanf-specific handlers.<br>
+<br>
+ virtual bool HandleInvalidScanfConversionSpecifier(<br>
+ const analyze_scanf::ScanfSpecifier &FS,<br>
+ const char *startSpecifier,<br>
+ unsigned specifierLen) {<br>
+ return true;<br>
+ }<br>
+<br>
+ virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,<br>
+ const char *startSpecifier,<br>
+ unsigned specifierLen) {<br>
+ return true;<br>
+ }<br>
+<br>
+ virtual void HandleIncompleteScanList(const char *start, const char *end) {}<br>
+};<br>
+<br>
+bool ParsePrintfString(FormatStringHandler &H,<br>
+ const char *beg, const char *end, const LangOptions &LO,<br>
+ const TargetInfo &Target, bool isFreeBSDKPrintf);<br>
+<br>
+bool ParseFormatStringHasSArg(const char *beg, const char *end,<br>
+ const LangOptions &LO, const TargetInfo &Target);<br>
+<br>
+bool ParseScanfString(FormatStringHandler &H,<br>
+ const char *beg, const char *end, const LangOptions &LO,<br>
+ const TargetInfo &Target);<br>
+<br>
+} // end analyze_format_string namespace<br>
+} // end clang namespace<br>
+#endif<br>
<br>
Added: cfe/trunk/include/clang/AST/OSLog.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/OSLog.h?rev=345971&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/OSLog.h?rev=345971&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/AST/OSLog.h (added)<br>
+++ cfe/trunk/include/clang/AST/OSLog.h Fri Nov 2 06:14:11 2018<br>
@@ -0,0 +1,155 @@<br>
+//= OSLog.h - Analysis of calls to os_log builtins --*- C++ -*-===============//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+// This file defines APIs for determining the layout of the data buffer for<br>
+// os_log() and os_trace().<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H<br>
+#define LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H<br>
+<br>
+#include "clang/AST/ASTContext.h"<br>
+#include "clang/AST/Expr.h"<br>
+<br>
+namespace clang {<br>
+namespace analyze_os_log {<br>
+<br>
+/// An OSLogBufferItem represents a single item in the data written by a call<br>
+/// to os_log() or os_trace().<br>
+class OSLogBufferItem {<br>
+public:<br>
+ enum Kind {<br>
+ // The item is a scalar (int, float, raw pointer, etc.). No further copying<br>
+ // is required. This is the only kind allowed by os_trace().<br>
+ ScalarKind = 0,<br>
+<br>
+ // The item is a count, which describes the length of the following item to<br>
+ // be copied. A count may only be followed by an item of kind StringKind,<br>
+ // WideStringKind, or PointerKind.<br>
+ CountKind,<br>
+<br>
+ // The item is a pointer to a C string. If preceded by a count 'n',<br>
+ // os_log() will copy at most 'n' bytes from the pointer.<br>
+ StringKind,<br>
+<br>
+ // The item is a pointer to a block of raw data. This item must be preceded<br>
+ // by a count 'n'. os_log() will copy exactly 'n' bytes from the pointer.<br>
+ PointerKind,<br>
+<br>
+ // The item is a pointer to an Objective-C object. os_log() may retain the<br>
+ // object for later processing.<br>
+ ObjCObjKind,<br>
+<br>
+ // The item is a pointer to wide-char string.<br>
+ WideStringKind,<br>
+<br>
+ // The item is corresponding to the '%m' format specifier, no value is<br>
+ // populated in the buffer and the runtime is loading the errno value.<br>
+ ErrnoKind<br>
+ };<br>
+<br>
+ enum {<br>
+ // The item is marked "private" in the format string.<br>
+ IsPrivate = 0x1,<br>
+<br>
+ // The item is marked "public" in the format string.<br>
+ IsPublic = 0x2<br>
+ };<br>
+<br>
+private:<br>
+ Kind TheKind = ScalarKind;<br>
+ const Expr *TheExpr = nullptr;<br>
+ CharUnits ConstValue;<br>
+ CharUnits Size; // size of the data, not including the header bytes<br>
+ unsigned Flags = 0;<br>
+<br>
+public:<br>
+ OSLogBufferItem(Kind kind, const Expr *expr, CharUnits size, unsigned flags)<br>
+ : TheKind(kind), TheExpr(expr), Size(size), Flags(flags) {}<br>
+<br>
+ OSLogBufferItem(ASTContext &Ctx, CharUnits value, unsigned flags)<br>
+ : TheKind(CountKind), ConstValue(value),<br>
+ Size(Ctx.getTypeSizeInChars(Ctx.IntTy)), Flags(flags) {}<br>
+<br>
+ unsigned char getDescriptorByte() const {<br>
+ unsigned char result = 0;<br>
+ if (getIsPrivate())<br>
+ result |= IsPrivate;<br>
+ if (getIsPublic())<br>
+ result |= IsPublic;<br>
+ result |= ((unsigned)getKind()) << 4;<br>
+ return result;<br>
+ }<br>
+<br>
+ unsigned char getSizeByte() const { return size().getQuantity(); }<br>
+<br>
+ Kind getKind() const { return TheKind; }<br>
+ bool getIsPrivate() const { return (Flags & IsPrivate) != 0; }<br>
+ bool getIsPublic() const { return (Flags & IsPublic) != 0; }<br>
+<br>
+ const Expr *getExpr() const { return TheExpr; }<br>
+ CharUnits getConstValue() const { return ConstValue; }<br>
+ CharUnits size() const { return Size; }<br>
+};<br>
+<br>
+class OSLogBufferLayout {<br>
+public:<br>
+ SmallVector<OSLogBufferItem, 4> Items;<br>
+<br>
+ enum Flags { HasPrivateItems = 1, HasNonScalarItems = 1 << 1 };<br>
+<br>
+ CharUnits size() const {<br>
+ CharUnits result;<br>
+ result += CharUnits::fromQuantity(2); // summary byte, num-args byte<br>
+ for (auto &item : Items) {<br>
+ // descriptor byte, size byte<br>
+ result += item.size() + CharUnits::fromQuantity(2);<br>
+ }<br>
+ return result;<br>
+ }<br>
+<br>
+ bool hasPrivateItems() const {<br>
+ return llvm::any_of(<br>
+ Items, [](const OSLogBufferItem &Item) { return Item.getIsPrivate(); });<br>
+ }<br>
+<br>
+ bool hasPublicItems() const {<br>
+ return llvm::any_of(<br>
+ Items, [](const OSLogBufferItem &Item) { return Item.getIsPublic(); });<br>
+ }<br>
+<br>
+ bool hasNonScalar() const {<br>
+ return llvm::any_of(Items, [](const OSLogBufferItem &Item) {<br>
+ return Item.getKind() != OSLogBufferItem::ScalarKind;<br>
+ });<br>
+ }<br>
+<br>
+ unsigned char getSummaryByte() const {<br>
+ unsigned char result = 0;<br>
+ if (hasPrivateItems())<br>
+ result |= HasPrivateItems;<br>
+ if (hasNonScalar())<br>
+ result |= HasNonScalarItems;<br>
+ return result;<br>
+ }<br>
+<br>
+ unsigned char getNumArgsByte() const { return Items.size(); }<br>
+};<br>
+<br>
+// Given a call 'E' to one of the builtins __builtin_os_log_format() or<br>
+// __builtin_os_log_format_buffer_size(), compute the layout of the buffer that<br>
+// the call will write into and store it in 'layout'. Returns 'false' if there<br>
+// was some error encountered while computing the layout, and 'true' otherwise.<br>
+bool computeOSLogBufferLayout(clang::ASTContext &Ctx, const clang::CallExpr *E,<br>
+ OSLogBufferLayout &layout);<br>
+<br>
+} // namespace analyze_os_log<br>
+} // namespace clang<br>
+#endif<br>
<br>
Removed: cfe/trunk/include/clang/Analysis/Analyses/FormatString.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/FormatString.h?rev=345970&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/FormatString.h?rev=345970&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Analysis/Analyses/FormatString.h (original)<br>
+++ cfe/trunk/include/clang/Analysis/Analyses/FormatString.h (removed)<br>
@@ -1,719 +0,0 @@<br>
-//= FormatString.h - Analysis of printf/fprintf format strings --*- C++ -*-===//<br>
-//<br>
-// The LLVM Compiler Infrastructure<br>
-//<br>
-// This file is distributed under the University of Illinois Open Source<br>
-// License. See LICENSE.TXT for details.<br>
-//<br>
-//===----------------------------------------------------------------------===//<br>
-//<br>
-// This file defines APIs for analyzing the format strings of printf, fscanf,<br>
-// and friends.<br>
-//<br>
-// The structure of format strings for fprintf are described in C99 7.19.6.1.<br>
-//<br>
-// The structure of format strings for fscanf are described in C99 7.19.6.2.<br>
-//<br>
-//===----------------------------------------------------------------------===//<br>
-<br>
-#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H<br>
-#define LLVM_CLANG_ANALYSIS_ANALYSES_FORMATSTRING_H<br>
-<br>
-#include "clang/AST/CanonicalType.h"<br>
-<br>
-namespace clang {<br>
-<br>
-class TargetInfo;<br>
-<br>
-//===----------------------------------------------------------------------===//<br>
-/// Common components of both fprintf and fscanf format strings.<br>
-namespace analyze_format_string {<br>
-<br>
-/// Class representing optional flags with location and representation<br>
-/// information.<br>
-class OptionalFlag {<br>
-public:<br>
- OptionalFlag(const char *Representation)<br>
- : representation(Representation), flag(false) {}<br>
- bool isSet() const { return flag; }<br>
- void set() { flag = true; }<br>
- void clear() { flag = false; }<br>
- void setPosition(const char *position) {<br>
- assert(position);<br>
- flag = true;<br>
- this->position = position;<br>
- }<br>
- const char *getPosition() const {<br>
- assert(position);<br>
- return position;<br>
- }<br>
- const char *toString() const { return representation; }<br>
-<br>
- // Overloaded operators for bool like qualities<br>
- explicit operator bool() const { return flag; }<br>
- OptionalFlag& operator=(const bool &rhs) {<br>
- flag = rhs;<br>
- return *this; // Return a reference to myself.<br>
- }<br>
-private:<br>
- const char *representation;<br>
- const char *position;<br>
- bool flag;<br>
-};<br>
-<br>
-/// Represents the length modifier in a format string in scanf/printf.<br>
-class LengthModifier {<br>
-public:<br>
- enum Kind {<br>
- None,<br>
- AsChar, // 'hh'<br>
- AsShort, // 'h'<br>
- AsLong, // 'l'<br>
- AsLongLong, // 'll'<br>
- AsQuad, // 'q' (BSD, deprecated, for 64-bit integer types)<br>
- AsIntMax, // 'j'<br>
- AsSizeT, // 'z'<br>
- AsPtrDiff, // 't'<br>
- AsInt32, // 'I32' (MSVCRT, like __int32)<br>
- AsInt3264, // 'I' (MSVCRT, like __int3264 from MIDL)<br>
- AsInt64, // 'I64' (MSVCRT, like __int64)<br>
- AsLongDouble, // 'L'<br>
- AsAllocate, // for '%as', GNU extension to C90 scanf<br>
- AsMAllocate, // for '%ms', GNU extension to scanf<br>
- AsWide, // 'w' (MSVCRT, like l but only for c, C, s, S, or Z<br>
- AsWideChar = AsLong // for '%ls', only makes sense for printf<br>
- };<br>
-<br>
- LengthModifier()<br>
- : Position(nullptr), kind(None) {}<br>
- LengthModifier(const char *pos, Kind k)<br>
- : Position(pos), kind(k) {}<br>
-<br>
- const char *getStart() const {<br>
- return Position;<br>
- }<br>
-<br>
- unsigned getLength() const {<br>
- switch (kind) {<br>
- default:<br>
- return 1;<br>
- case AsLongLong:<br>
- case AsChar:<br>
- return 2;<br>
- case AsInt32:<br>
- case AsInt64:<br>
- return 3;<br>
- case None:<br>
- return 0;<br>
- }<br>
- }<br>
-<br>
- Kind getKind() const { return kind; }<br>
- void setKind(Kind k) { kind = k; }<br>
-<br>
- const char *toString() const;<br>
-<br>
-private:<br>
- const char *Position;<br>
- Kind kind;<br>
-};<br>
-<br>
-class ConversionSpecifier {<br>
-public:<br>
- enum Kind {<br>
- InvalidSpecifier = 0,<br>
- // C99 conversion specifiers.<br>
- cArg,<br>
- dArg,<br>
- DArg, // Apple extension<br>
- iArg,<br>
- IntArgBeg = dArg,<br>
- IntArgEnd = iArg,<br>
-<br>
- oArg,<br>
- OArg, // Apple extension<br>
- uArg,<br>
- UArg, // Apple extension<br>
- xArg,<br>
- XArg,<br>
- UIntArgBeg = oArg,<br>
- UIntArgEnd = XArg,<br>
-<br>
- fArg,<br>
- FArg,<br>
- eArg,<br>
- EArg,<br>
- gArg,<br>
- GArg,<br>
- aArg,<br>
- AArg,<br>
- DoubleArgBeg = fArg,<br>
- DoubleArgEnd = AArg,<br>
-<br>
- sArg,<br>
- pArg,<br>
- nArg,<br>
- PercentArg,<br>
- CArg,<br>
- SArg,<br>
-<br>
- // Apple extension: P specifies to os_log that the data being pointed to is<br>
- // to be copied by os_log. The precision indicates the number of bytes to<br>
- // copy.<br>
- PArg,<br>
-<br>
- // ** Printf-specific **<br>
-<br>
- ZArg, // MS extension<br>
-<br>
- // Objective-C specific specifiers.<br>
- ObjCObjArg, // '@'<br>
- ObjCBeg = ObjCObjArg,<br>
- ObjCEnd = ObjCObjArg,<br>
-<br>
- // FreeBSD kernel specific specifiers.<br>
- FreeBSDbArg,<br>
- FreeBSDDArg,<br>
- FreeBSDrArg,<br>
- FreeBSDyArg,<br>
-<br>
- // GlibC specific specifiers.<br>
- PrintErrno, // 'm'<br>
-<br>
- PrintfConvBeg = ObjCObjArg,<br>
- PrintfConvEnd = PrintErrno,<br>
-<br>
- // ** Scanf-specific **<br>
- ScanListArg, // '['<br>
- ScanfConvBeg = ScanListArg,<br>
- ScanfConvEnd = ScanListArg<br>
- };<br>
-<br>
- ConversionSpecifier(bool isPrintf = true)<br>
- : IsPrintf(isPrintf), Position(nullptr), EndScanList(nullptr),<br>
- kind(InvalidSpecifier) {}<br>
-<br>
- ConversionSpecifier(bool isPrintf, const char *pos, Kind k)<br>
- : IsPrintf(isPrintf), Position(pos), EndScanList(nullptr), kind(k) {}<br>
-<br>
- const char *getStart() const {<br>
- return Position;<br>
- }<br>
-<br>
- StringRef getCharacters() const {<br>
- return StringRef(getStart(), getLength());<br>
- }<br>
-<br>
- bool consumesDataArgument() const {<br>
- switch (kind) {<br>
- case PrintErrno:<br>
- assert(IsPrintf);<br>
- return false;<br>
- case PercentArg:<br>
- return false;<br>
- case InvalidSpecifier:<br>
- return false;<br>
- default:<br>
- return true;<br>
- }<br>
- }<br>
-<br>
- Kind getKind() const { return kind; }<br>
- void setKind(Kind k) { kind = k; }<br>
- unsigned getLength() const {<br>
- return EndScanList ? EndScanList - Position : 1;<br>
- }<br>
- void setEndScanList(const char *pos) { EndScanList = pos; }<br>
-<br>
- bool isIntArg() const { return (kind >= IntArgBeg && kind <= IntArgEnd) ||<br>
- kind == FreeBSDrArg || kind == FreeBSDyArg; }<br>
- bool isUIntArg() const { return kind >= UIntArgBeg && kind <= UIntArgEnd; }<br>
- bool isAnyIntArg() const { return kind >= IntArgBeg && kind <= UIntArgEnd; }<br>
- bool isDoubleArg() const {<br>
- return kind >= DoubleArgBeg && kind <= DoubleArgEnd;<br>
- }<br>
-<br>
- const char *toString() const;<br>
-<br>
- bool isPrintfKind() const { return IsPrintf; }<br>
-<br>
- Optional<ConversionSpecifier> getStandardSpecifier() const;<br>
-<br>
-protected:<br>
- bool IsPrintf;<br>
- const char *Position;<br>
- const char *EndScanList;<br>
- Kind kind;<br>
-};<br>
-<br>
-class ArgType {<br>
-public:<br>
- enum Kind { UnknownTy, InvalidTy, SpecificTy, ObjCPointerTy, CPointerTy,<br>
- AnyCharTy, CStrTy, WCStrTy, WIntTy };<br>
-<br>
- enum MatchKind { NoMatch = 0, Match = 1, NoMatchPedantic };<br>
-<br>
-private:<br>
- const Kind K;<br>
- QualType T;<br>
- const char *Name = nullptr;<br>
- bool Ptr = false;<br>
-<br>
- /// The TypeKind identifies certain well-known types like size_t and<br>
- /// ptrdiff_t.<br>
- enum class TypeKind { DontCare, SizeT, PtrdiffT };<br>
- TypeKind TK = TypeKind::DontCare;<br>
-<br>
-public:<br>
- ArgType(Kind K = UnknownTy, const char *N = nullptr) : K(K), Name(N) {}<br>
- ArgType(QualType T, const char *N = nullptr) : K(SpecificTy), T(T), Name(N) {}<br>
- ArgType(CanQualType T) : K(SpecificTy), T(T) {}<br>
-<br>
- static ArgType Invalid() { return ArgType(InvalidTy); }<br>
- bool isValid() const { return K != InvalidTy; }<br>
-<br>
- bool isSizeT() const { return TK == TypeKind::SizeT; }<br>
-<br>
- bool isPtrdiffT() const { return TK == TypeKind::PtrdiffT; }<br>
-<br>
- /// Create an ArgType which corresponds to the type pointer to A.<br>
- static ArgType PtrTo(const ArgType& A) {<br>
- assert(A.K >= InvalidTy && "ArgType cannot be pointer to invalid/unknown");<br>
- ArgType Res = A;<br>
- Res.Ptr = true;<br>
- return Res;<br>
- }<br>
-<br>
- /// Create an ArgType which corresponds to the size_t/ssize_t type.<br>
- static ArgType makeSizeT(const ArgType &A) {<br>
- ArgType Res = A;<br>
- Res.TK = TypeKind::SizeT;<br>
- return Res;<br>
- }<br>
-<br>
- /// Create an ArgType which corresponds to the ptrdiff_t/unsigned ptrdiff_t<br>
- /// type.<br>
- static ArgType makePtrdiffT(const ArgType &A) {<br>
- ArgType Res = A;<br>
- Res.TK = TypeKind::PtrdiffT;<br>
- return Res;<br>
- }<br>
-<br>
- MatchKind matchesType(ASTContext &C, QualType argTy) const;<br>
-<br>
- QualType getRepresentativeType(ASTContext &C) const;<br>
-<br>
- std::string getRepresentativeTypeName(ASTContext &C) const;<br>
-};<br>
-<br>
-class OptionalAmount {<br>
-public:<br>
- enum HowSpecified { NotSpecified, Constant, Arg, Invalid };<br>
-<br>
- OptionalAmount(HowSpecified howSpecified,<br>
- unsigned amount,<br>
- const char *amountStart,<br>
- unsigned amountLength,<br>
- bool usesPositionalArg)<br>
- : start(amountStart), length(amountLength), hs(howSpecified), amt(amount),<br>
- UsesPositionalArg(usesPositionalArg), UsesDotPrefix(0) {}<br>
-<br>
- OptionalAmount(bool valid = true)<br>
- : start(nullptr),length(0), hs(valid ? NotSpecified : Invalid), amt(0),<br>
- UsesPositionalArg(0), UsesDotPrefix(0) {}<br>
-<br>
- bool isInvalid() const {<br>
- return hs == Invalid;<br>
- }<br>
-<br>
- HowSpecified getHowSpecified() const { return hs; }<br>
- void setHowSpecified(HowSpecified h) { hs = h; }<br>
-<br>
- bool hasDataArgument() const { return hs == Arg; }<br>
-<br>
- unsigned getArgIndex() const {<br>
- assert(hasDataArgument());<br>
- return amt;<br>
- }<br>
-<br>
- unsigned getConstantAmount() const {<br>
- assert(hs == Constant);<br>
- return amt;<br>
- }<br>
-<br>
- const char *getStart() const {<br>
- // We include the . character if it is given.<br>
- return start - UsesDotPrefix;<br>
- }<br>
-<br>
- unsigned getConstantLength() const {<br>
- assert(hs == Constant);<br>
- return length + UsesDotPrefix;<br>
- }<br>
-<br>
- ArgType getArgType(ASTContext &Ctx) const;<br>
-<br>
- void toString(raw_ostream &os) const;<br>
-<br>
- bool usesPositionalArg() const { return (bool) UsesPositionalArg; }<br>
- unsigned getPositionalArgIndex() const {<br>
- assert(hasDataArgument());<br>
- return amt + 1;<br>
- }<br>
-<br>
- bool usesDotPrefix() const { return UsesDotPrefix; }<br>
- void setUsesDotPrefix() { UsesDotPrefix = true; }<br>
-<br>
-private:<br>
- const char *start;<br>
- unsigned length;<br>
- HowSpecified hs;<br>
- unsigned amt;<br>
- bool UsesPositionalArg : 1;<br>
- bool UsesDotPrefix;<br>
-};<br>
-<br>
-<br>
-class FormatSpecifier {<br>
-protected:<br>
- LengthModifier LM;<br>
- OptionalAmount FieldWidth;<br>
- ConversionSpecifier CS;<br>
- /// Positional arguments, an IEEE extension:<br>
- /// IEEE Std 1003.1, 2004 Edition<br>
- /// <a href="http://www.opengroup.org/onlinepubs/009695399/functions/printf.html" rel="noreferrer" target="_blank">http://www.opengroup.org/onlinepubs/009695399/functions/printf.html</a><br>
- bool UsesPositionalArg;<br>
- unsigned argIndex;<br>
-public:<br>
- FormatSpecifier(bool isPrintf)<br>
- : CS(isPrintf), UsesPositionalArg(false), argIndex(0) {}<br>
-<br>
- void setLengthModifier(LengthModifier lm) {<br>
- LM = lm;<br>
- }<br>
-<br>
- void setUsesPositionalArg() { UsesPositionalArg = true; }<br>
-<br>
- void setArgIndex(unsigned i) {<br>
- argIndex = i;<br>
- }<br>
-<br>
- unsigned getArgIndex() const {<br>
- return argIndex;<br>
- }<br>
-<br>
- unsigned getPositionalArgIndex() const {<br>
- return argIndex + 1;<br>
- }<br>
-<br>
- const LengthModifier &getLengthModifier() const {<br>
- return LM;<br>
- }<br>
-<br>
- const OptionalAmount &getFieldWidth() const {<br>
- return FieldWidth;<br>
- }<br>
-<br>
- void setFieldWidth(const OptionalAmount &Amt) {<br>
- FieldWidth = Amt;<br>
- }<br>
-<br>
- bool usesPositionalArg() const { return UsesPositionalArg; }<br>
-<br>
- bool hasValidLengthModifier(const TargetInfo &Target) const;<br>
-<br>
- bool hasStandardLengthModifier() const;<br>
-<br>
- Optional<LengthModifier> getCorrectedLengthModifier() const;<br>
-<br>
- bool hasStandardConversionSpecifier(const LangOptions &LangOpt) const;<br>
-<br>
- bool hasStandardLengthConversionCombination() const;<br>
-<br>
- /// For a TypedefType QT, if it is a named integer type such as size_t,<br>
- /// assign the appropriate value to LM and return true.<br>
- static bool namedTypeToLengthModifier(QualType QT, LengthModifier &LM);<br>
-};<br>
-<br>
-} // end analyze_format_string namespace<br>
-<br>
-//===----------------------------------------------------------------------===//<br>
-/// Pieces specific to fprintf format strings.<br>
-<br>
-namespace analyze_printf {<br>
-<br>
-class PrintfConversionSpecifier :<br>
- public analyze_format_string::ConversionSpecifier {<br>
-public:<br>
- PrintfConversionSpecifier()<br>
- : ConversionSpecifier(true, nullptr, InvalidSpecifier) {}<br>
-<br>
- PrintfConversionSpecifier(const char *pos, Kind k)<br>
- : ConversionSpecifier(true, pos, k) {}<br>
-<br>
- bool isObjCArg() const { return kind >= ObjCBeg && kind <= ObjCEnd; }<br>
- bool isDoubleArg() const { return kind >= DoubleArgBeg &&<br>
- kind <= DoubleArgEnd; }<br>
-<br>
- static bool classof(const analyze_format_string::ConversionSpecifier *CS) {<br>
- return CS->isPrintfKind();<br>
- }<br>
-};<br>
-<br>
-using analyze_format_string::ArgType;<br>
-using analyze_format_string::LengthModifier;<br>
-using analyze_format_string::OptionalAmount;<br>
-using analyze_format_string::OptionalFlag;<br>
-<br>
-class PrintfSpecifier : public analyze_format_string::FormatSpecifier {<br>
- OptionalFlag HasThousandsGrouping; // ''', POSIX extension.<br>
- OptionalFlag IsLeftJustified; // '-'<br>
- OptionalFlag HasPlusPrefix; // '+'<br>
- OptionalFlag HasSpacePrefix; // ' '<br>
- OptionalFlag HasAlternativeForm; // '#'<br>
- OptionalFlag HasLeadingZeroes; // '0'<br>
- OptionalFlag HasObjCTechnicalTerm; // '[tt]'<br>
- OptionalFlag IsPrivate; // '{private}'<br>
- OptionalFlag IsPublic; // '{public}'<br>
- OptionalAmount Precision;<br>
-public:<br>
- PrintfSpecifier()<br>
- : FormatSpecifier(/* isPrintf = */ true), HasThousandsGrouping("'"),<br>
- IsLeftJustified("-"), HasPlusPrefix("+"), HasSpacePrefix(" "),<br>
- HasAlternativeForm("#"), HasLeadingZeroes("0"),<br>
- HasObjCTechnicalTerm("tt"), IsPrivate("private"), IsPublic("public") {}<br>
-<br>
- static PrintfSpecifier Parse(const char *beg, const char *end);<br>
-<br>
- // Methods for incrementally constructing the PrintfSpecifier.<br>
- void setConversionSpecifier(const PrintfConversionSpecifier &cs) {<br>
- CS = cs;<br>
- }<br>
- void setHasThousandsGrouping(const char *position) {<br>
- HasThousandsGrouping.setPosition(position);<br>
- }<br>
- void setIsLeftJustified(const char *position) {<br>
- IsLeftJustified.setPosition(position);<br>
- }<br>
- void setHasPlusPrefix(const char *position) {<br>
- HasPlusPrefix.setPosition(position);<br>
- }<br>
- void setHasSpacePrefix(const char *position) {<br>
- HasSpacePrefix.setPosition(position);<br>
- }<br>
- void setHasAlternativeForm(const char *position) {<br>
- HasAlternativeForm.setPosition(position);<br>
- }<br>
- void setHasLeadingZeros(const char *position) {<br>
- HasLeadingZeroes.setPosition(position);<br>
- }<br>
- void setHasObjCTechnicalTerm(const char *position) {<br>
- HasObjCTechnicalTerm.setPosition(position);<br>
- }<br>
- void setIsPrivate(const char *position) { IsPrivate.setPosition(position); }<br>
- void setIsPublic(const char *position) { IsPublic.setPosition(position); }<br>
- void setUsesPositionalArg() { UsesPositionalArg = true; }<br>
-<br>
- // Methods for querying the format specifier.<br>
-<br>
- const PrintfConversionSpecifier &getConversionSpecifier() const {<br>
- return cast<PrintfConversionSpecifier>(CS);<br>
- }<br>
-<br>
- void setPrecision(const OptionalAmount &Amt) {<br>
- Precision = Amt;<br>
- Precision.setUsesDotPrefix();<br>
- }<br>
-<br>
- const OptionalAmount &getPrecision() const {<br>
- return Precision;<br>
- }<br>
-<br>
- bool consumesDataArgument() const {<br>
- return getConversionSpecifier().consumesDataArgument();<br>
- }<br>
-<br>
- /// Returns the builtin type that a data argument<br>
- /// paired with this format specifier should have. This method<br>
- /// will return null if the format specifier does not have<br>
- /// a matching data argument or the matching argument matches<br>
- /// more than one type.<br>
- ArgType getArgType(ASTContext &Ctx, bool IsObjCLiteral) const;<br>
-<br>
- const OptionalFlag &hasThousandsGrouping() const {<br>
- return HasThousandsGrouping;<br>
- }<br>
- const OptionalFlag &isLeftJustified() const { return IsLeftJustified; }<br>
- const OptionalFlag &hasPlusPrefix() const { return HasPlusPrefix; }<br>
- const OptionalFlag &hasAlternativeForm() const { return HasAlternativeForm; }<br>
- const OptionalFlag &hasLeadingZeros() const { return HasLeadingZeroes; }<br>
- const OptionalFlag &hasSpacePrefix() const { return HasSpacePrefix; }<br>
- const OptionalFlag &hasObjCTechnicalTerm() const { return HasObjCTechnicalTerm; }<br>
- const OptionalFlag &isPrivate() const { return IsPrivate; }<br>
- const OptionalFlag &isPublic() const { return IsPublic; }<br>
- bool usesPositionalArg() const { return UsesPositionalArg; }<br>
-<br>
- /// Changes the specifier and length according to a QualType, retaining any<br>
- /// flags or options. Returns true on success, or false when a conversion<br>
- /// was not successful.<br>
- bool fixType(QualType QT, const LangOptions &LangOpt, ASTContext &Ctx,<br>
- bool IsObjCLiteral);<br>
-<br>
- void toString(raw_ostream &os) const;<br>
-<br>
- // Validation methods - to check if any element results in undefined behavior<br>
- bool hasValidPlusPrefix() const;<br>
- bool hasValidAlternativeForm() const;<br>
- bool hasValidLeadingZeros() const;<br>
- bool hasValidSpacePrefix() const;<br>
- bool hasValidLeftJustified() const;<br>
- bool hasValidThousandsGroupingPrefix() const;<br>
-<br>
- bool hasValidPrecision() const;<br>
- bool hasValidFieldWidth() const;<br>
-};<br>
-} // end analyze_printf namespace<br>
-<br>
-//===----------------------------------------------------------------------===//<br>
-/// Pieces specific to fscanf format strings.<br>
-<br>
-namespace analyze_scanf {<br>
-<br>
-class ScanfConversionSpecifier :<br>
- public analyze_format_string::ConversionSpecifier {<br>
-public:<br>
- ScanfConversionSpecifier()<br>
- : ConversionSpecifier(false, nullptr, InvalidSpecifier) {}<br>
-<br>
- ScanfConversionSpecifier(const char *pos, Kind k)<br>
- : ConversionSpecifier(false, pos, k) {}<br>
-<br>
- static bool classof(const analyze_format_string::ConversionSpecifier *CS) {<br>
- return !CS->isPrintfKind();<br>
- }<br>
-};<br>
-<br>
-using analyze_format_string::ArgType;<br>
-using analyze_format_string::LengthModifier;<br>
-using analyze_format_string::OptionalAmount;<br>
-using analyze_format_string::OptionalFlag;<br>
-<br>
-class ScanfSpecifier : public analyze_format_string::FormatSpecifier {<br>
- OptionalFlag SuppressAssignment; // '*'<br>
-public:<br>
- ScanfSpecifier() :<br>
- FormatSpecifier(/* isPrintf = */ false),<br>
- SuppressAssignment("*") {}<br>
-<br>
- void setSuppressAssignment(const char *position) {<br>
- SuppressAssignment.setPosition(position);<br>
- }<br>
-<br>
- const OptionalFlag &getSuppressAssignment() const {<br>
- return SuppressAssignment;<br>
- }<br>
-<br>
- void setConversionSpecifier(const ScanfConversionSpecifier &cs) {<br>
- CS = cs;<br>
- }<br>
-<br>
- const ScanfConversionSpecifier &getConversionSpecifier() const {<br>
- return cast<ScanfConversionSpecifier>(CS);<br>
- }<br>
-<br>
- bool consumesDataArgument() const {<br>
- return CS.consumesDataArgument() && !SuppressAssignment;<br>
- }<br>
-<br>
- ArgType getArgType(ASTContext &Ctx) const;<br>
-<br>
- bool fixType(QualType QT, QualType RawQT, const LangOptions &LangOpt,<br>
- ASTContext &Ctx);<br>
-<br>
- void toString(raw_ostream &os) const;<br>
-<br>
- static ScanfSpecifier Parse(const char *beg, const char *end);<br>
-};<br>
-<br>
-} // end analyze_scanf namespace<br>
-<br>
-//===----------------------------------------------------------------------===//<br>
-// Parsing and processing of format strings (both fprintf and fscanf).<br>
-<br>
-namespace analyze_format_string {<br>
-<br>
-enum PositionContext { FieldWidthPos = 0, PrecisionPos = 1 };<br>
-<br>
-class FormatStringHandler {<br>
-public:<br>
- FormatStringHandler() {}<br>
- virtual ~FormatStringHandler();<br>
-<br>
- virtual void HandleNullChar(const char *nullCharacter) {}<br>
-<br>
- virtual void HandlePosition(const char *startPos, unsigned posLen) {}<br>
-<br>
- virtual void HandleInvalidPosition(const char *startPos, unsigned posLen,<br>
- PositionContext p) {}<br>
-<br>
- virtual void HandleZeroPosition(const char *startPos, unsigned posLen) {}<br>
-<br>
- virtual void HandleIncompleteSpecifier(const char *startSpecifier,<br>
- unsigned specifierLen) {}<br>
-<br>
- virtual void HandleEmptyObjCModifierFlag(const char *startFlags,<br>
- unsigned flagsLen) {}<br>
-<br>
- virtual void HandleInvalidObjCModifierFlag(const char *startFlag,<br>
- unsigned flagLen) {}<br>
-<br>
- virtual void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart,<br>
- const char *flagsEnd,<br>
- const char *conversionPosition) {}<br>
- // Printf-specific handlers.<br>
-<br>
- virtual bool HandleInvalidPrintfConversionSpecifier(<br>
- const analyze_printf::PrintfSpecifier &FS,<br>
- const char *startSpecifier,<br>
- unsigned specifierLen) {<br>
- return true;<br>
- }<br>
-<br>
- virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,<br>
- const char *startSpecifier,<br>
- unsigned specifierLen) {<br>
- return true;<br>
- }<br>
-<br>
- // Scanf-specific handlers.<br>
-<br>
- virtual bool HandleInvalidScanfConversionSpecifier(<br>
- const analyze_scanf::ScanfSpecifier &FS,<br>
- const char *startSpecifier,<br>
- unsigned specifierLen) {<br>
- return true;<br>
- }<br>
-<br>
- virtual bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,<br>
- const char *startSpecifier,<br>
- unsigned specifierLen) {<br>
- return true;<br>
- }<br>
-<br>
- virtual void HandleIncompleteScanList(const char *start, const char *end) {}<br>
-};<br>
-<br>
-bool ParsePrintfString(FormatStringHandler &H,<br>
- const char *beg, const char *end, const LangOptions &LO,<br>
- const TargetInfo &Target, bool isFreeBSDKPrintf);<br>
-<br>
-bool ParseFormatStringHasSArg(const char *beg, const char *end,<br>
- const LangOptions &LO, const TargetInfo &Target);<br>
-<br>
-bool ParseScanfString(FormatStringHandler &H,<br>
- const char *beg, const char *end, const LangOptions &LO,<br>
- const TargetInfo &Target);<br>
-<br>
-} // end analyze_format_string namespace<br>
-} // end clang namespace<br>
-#endif<br>
<br>
Removed: cfe/trunk/include/clang/Analysis/Analyses/OSLog.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/OSLog.h?rev=345970&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/OSLog.h?rev=345970&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Analysis/Analyses/OSLog.h (original)<br>
+++ cfe/trunk/include/clang/Analysis/Analyses/OSLog.h (removed)<br>
@@ -1,155 +0,0 @@<br>
-//= OSLog.h - Analysis of calls to os_log builtins --*- C++ -*-===============//<br>
-//<br>
-// The LLVM Compiler Infrastructure<br>
-//<br>
-// This file is distributed under the University of Illinois Open Source<br>
-// License. See LICENSE.TXT for details.<br>
-//<br>
-//===----------------------------------------------------------------------===//<br>
-//<br>
-// This file defines APIs for determining the layout of the data buffer for<br>
-// os_log() and os_trace().<br>
-//<br>
-//===----------------------------------------------------------------------===//<br>
-<br>
-#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H<br>
-#define LLVM_CLANG_ANALYSIS_ANALYSES_OSLOG_H<br>
-<br>
-#include "clang/AST/ASTContext.h"<br>
-#include "clang/AST/Expr.h"<br>
-<br>
-namespace clang {<br>
-namespace analyze_os_log {<br>
-<br>
-/// An OSLogBufferItem represents a single item in the data written by a call<br>
-/// to os_log() or os_trace().<br>
-class OSLogBufferItem {<br>
-public:<br>
- enum Kind {<br>
- // The item is a scalar (int, float, raw pointer, etc.). No further copying<br>
- // is required. This is the only kind allowed by os_trace().<br>
- ScalarKind = 0,<br>
-<br>
- // The item is a count, which describes the length of the following item to<br>
- // be copied. A count may only be followed by an item of kind StringKind,<br>
- // WideStringKind, or PointerKind.<br>
- CountKind,<br>
-<br>
- // The item is a pointer to a C string. If preceded by a count 'n',<br>
- // os_log() will copy at most 'n' bytes from the pointer.<br>
- StringKind,<br>
-<br>
- // The item is a pointer to a block of raw data. This item must be preceded<br>
- // by a count 'n'. os_log() will copy exactly 'n' bytes from the pointer.<br>
- PointerKind,<br>
-<br>
- // The item is a pointer to an Objective-C object. os_log() may retain the<br>
- // object for later processing.<br>
- ObjCObjKind,<br>
-<br>
- // The item is a pointer to wide-char string.<br>
- WideStringKind,<br>
-<br>
- // The item is corresponding to the '%m' format specifier, no value is<br>
- // populated in the buffer and the runtime is loading the errno value.<br>
- ErrnoKind<br>
- };<br>
-<br>
- enum {<br>
- // The item is marked "private" in the format string.<br>
- IsPrivate = 0x1,<br>
-<br>
- // The item is marked "public" in the format string.<br>
- IsPublic = 0x2<br>
- };<br>
-<br>
-private:<br>
- Kind TheKind = ScalarKind;<br>
- const Expr *TheExpr = nullptr;<br>
- CharUnits ConstValue;<br>
- CharUnits Size; // size of the data, not including the header bytes<br>
- unsigned Flags = 0;<br>
-<br>
-public:<br>
- OSLogBufferItem(Kind kind, const Expr *expr, CharUnits size, unsigned flags)<br>
- : TheKind(kind), TheExpr(expr), Size(size), Flags(flags) {}<br>
-<br>
- OSLogBufferItem(ASTContext &Ctx, CharUnits value, unsigned flags)<br>
- : TheKind(CountKind), ConstValue(value),<br>
- Size(Ctx.getTypeSizeInChars(Ctx.IntTy)), Flags(flags) {}<br>
-<br>
- unsigned char getDescriptorByte() const {<br>
- unsigned char result = 0;<br>
- if (getIsPrivate())<br>
- result |= IsPrivate;<br>
- if (getIsPublic())<br>
- result |= IsPublic;<br>
- result |= ((unsigned)getKind()) << 4;<br>
- return result;<br>
- }<br>
-<br>
- unsigned char getSizeByte() const { return size().getQuantity(); }<br>
-<br>
- Kind getKind() const { return TheKind; }<br>
- bool getIsPrivate() const { return (Flags & IsPrivate) != 0; }<br>
- bool getIsPublic() const { return (Flags & IsPublic) != 0; }<br>
-<br>
- const Expr *getExpr() const { return TheExpr; }<br>
- CharUnits getConstValue() const { return ConstValue; }<br>
- CharUnits size() const { return Size; }<br>
-};<br>
-<br>
-class OSLogBufferLayout {<br>
-public:<br>
- SmallVector<OSLogBufferItem, 4> Items;<br>
-<br>
- enum Flags { HasPrivateItems = 1, HasNonScalarItems = 1 << 1 };<br>
-<br>
- CharUnits size() const {<br>
- CharUnits result;<br>
- result += CharUnits::fromQuantity(2); // summary byte, num-args byte<br>
- for (auto &item : Items) {<br>
- // descriptor byte, size byte<br>
- result += item.size() + CharUnits::fromQuantity(2);<br>
- }<br>
- return result;<br>
- }<br>
-<br>
- bool hasPrivateItems() const {<br>
- return llvm::any_of(<br>
- Items, [](const OSLogBufferItem &Item) { return Item.getIsPrivate(); });<br>
- }<br>
-<br>
- bool hasPublicItems() const {<br>
- return llvm::any_of(<br>
- Items, [](const OSLogBufferItem &Item) { return Item.getIsPublic(); });<br>
- }<br>
-<br>
- bool hasNonScalar() const {<br>
- return llvm::any_of(Items, [](const OSLogBufferItem &Item) {<br>
- return Item.getKind() != OSLogBufferItem::ScalarKind;<br>
- });<br>
- }<br>
-<br>
- unsigned char getSummaryByte() const {<br>
- unsigned char result = 0;<br>
- if (hasPrivateItems())<br>
- result |= HasPrivateItems;<br>
- if (hasNonScalar())<br>
- result |= HasNonScalarItems;<br>
- return result;<br>
- }<br>
-<br>
- unsigned char getNumArgsByte() const { return Items.size(); }<br>
-};<br>
-<br>
-// Given a call 'E' to one of the builtins __builtin_os_log_format() or<br>
-// __builtin_os_log_format_buffer_size(), compute the layout of the buffer that<br>
-// the call will write into and store it in 'layout'. Returns 'false' if there<br>
-// was some error encountered while computing the layout, and 'true' otherwise.<br>
-bool computeOSLogBufferLayout(clang::ASTContext &Ctx, const clang::CallExpr *E,<br>
- OSLogBufferLayout &layout);<br>
-<br>
-} // namespace analyze_os_log<br>
-} // namespace clang<br>
-#endif<br>
<br>
Modified: cfe/trunk/lib/AST/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CMakeLists.txt?rev=345971&r1=345970&r2=345971&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CMakeLists.txt?rev=345971&r1=345970&r2=345971&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/CMakeLists.txt (original)<br>
+++ cfe/trunk/lib/AST/CMakeLists.txt Fri Nov 2 06:14:11 2018<br>
@@ -39,6 +39,7 @@ add_clang_library(clangAST<br>
ExprObjC.cpp<br>
ExternalASTMerger.cpp<br>
ExternalASTSource.cpp<br>
+ FormatString.cpp<br>
InheritViz.cpp<br>
ItaniumCXXABI.cpp<br>
ItaniumMangle.cpp<br>
@@ -48,12 +49,15 @@ add_clang_library(clangAST<br>
NestedNameSpecifier.cpp<br>
NSAPI.cpp<br>
ODRHash.cpp<br>
+ OSLog.cpp<br>
OpenMPClause.cpp<br>
ParentMap.cpp<br>
+ PrintfFormatString.cpp<br>
QualTypeNames.cpp<br>
RawCommentList.cpp<br>
RecordLayout.cpp<br>
RecordLayoutBuilder.cpp<br>
+ ScanfFormatString.cpp<br>
SelectorLocationsKind.cpp<br>
Stmt.cpp<br>
StmtCXX.cpp<br>
<br>
Modified: cfe/trunk/lib/AST/ExprConstant.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=345971&r1=345970&r2=345971&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=345971&r1=345970&r2=345971&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)<br>
+++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Nov 2 06:14:11 2018<br>
@@ -39,6 +39,7 @@<br>
#include "clang/AST/ASTLambda.h"<br>
#include "clang/AST/CharUnits.h"<br>
#include "clang/AST/Expr.h"<br>
+#include "clang/AST/OSLog.h"<br>
#include "clang/AST/RecordLayout.h"<br>
#include "clang/AST/StmtVisitor.h"<br>
#include "clang/AST/TypeLoc.h"<br>
@@ -8126,6 +8127,12 @@ bool IntExprEvaluator::VisitBuiltinCallE<br>
llvm_unreachable("unexpected EvalMode");<br>
}<br>
<br>
+ case Builtin::BI__builtin_os_log_format_buffer_size: {<br>
+ analyze_os_log::OSLogBufferLayout Layout;<br>
+ analyze_os_log::computeOSLogBufferLayout(Info.Ctx, E, Layout);<br>
+ return Success(Layout.size().getQuantity(), E);<br>
+ }<br>
+<br>
case Builtin::BI__builtin_bswap16:<br>
case Builtin::BI__builtin_bswap32:<br>
case Builtin::BI__builtin_bswap64: {<br>
<br>
Added: cfe/trunk/lib/AST/FormatString.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/FormatString.cpp?rev=345971&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/FormatString.cpp?rev=345971&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/FormatString.cpp (added)<br>
+++ cfe/trunk/lib/AST/FormatString.cpp Fri Nov 2 06:14:11 2018<br>
@@ -0,0 +1,955 @@<br>
+// FormatString.cpp - Common stuff for handling printf/scanf formats -*- C++ -*-<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+// Shared details for processing format strings of printf and scanf<br>
+// (and friends).<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "FormatStringParsing.h"<br>
+#include "clang/Basic/LangOptions.h"<br>
+#include "clang/Basic/TargetInfo.h"<br>
+#include "llvm/Support/ConvertUTF.h"<br>
+<br>
+using clang::analyze_format_string::ArgType;<br>
+using clang::analyze_format_string::FormatStringHandler;<br>
+using clang::analyze_format_string::FormatSpecifier;<br>
+using clang::analyze_format_string::LengthModifier;<br>
+using clang::analyze_format_string::OptionalAmount;<br>
+using clang::analyze_format_string::PositionContext;<br>
+using clang::analyze_format_string::ConversionSpecifier;<br>
+using namespace clang;<br>
+<br>
+// Key function to FormatStringHandler.<br>
+FormatStringHandler::~FormatStringHandler() {}<br>
+<br>
+//===----------------------------------------------------------------------===//<br>
+// Functions for parsing format strings components in both printf and<br>
+// scanf format strings.<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+OptionalAmount<br>
+clang::analyze_format_string::ParseAmount(const char *&Beg, const char *E) {<br>
+ const char *I = Beg;<br>
+ UpdateOnReturn <const char*> UpdateBeg(Beg, I);<br>
+<br>
+ unsigned accumulator = 0;<br>
+ bool hasDigits = false;<br>
+<br>
+ for ( ; I != E; ++I) {<br>
+ char c = *I;<br>
+ if (c >= '0' && c <= '9') {<br>
+ hasDigits = true;<br>
+ accumulator = (accumulator * 10) + (c - '0');<br>
+ continue;<br>
+ }<br>
+<br>
+ if (hasDigits)<br>
+ return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg,<br>
+ false);<br>
+<br>
+ break;<br>
+ }<br>
+<br>
+ return OptionalAmount();<br>
+}<br>
+<br>
+OptionalAmount<br>
+clang::analyze_format_string::ParseNonPositionAmount(const char *&Beg,<br>
+ const char *E,<br>
+ unsigned &argIndex) {<br>
+ if (*Beg == '*') {<br>
+ ++Beg;<br>
+ return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);<br>
+ }<br>
+<br>
+ return ParseAmount(Beg, E);<br>
+}<br>
+<br>
+OptionalAmount<br>
+clang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H,<br>
+ const char *Start,<br>
+ const char *&Beg,<br>
+ const char *E,<br>
+ PositionContext p) {<br>
+ if (*Beg == '*') {<br>
+ const char *I = Beg + 1;<br>
+ const OptionalAmount &Amt = ParseAmount(I, E);<br>
+<br>
+ if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {<br>
+ H.HandleInvalidPosition(Beg, I - Beg, p);<br>
+ return OptionalAmount(false);<br>
+ }<br>
+<br>
+ if (I == E) {<br>
+ // No more characters left?<br>
+ H.HandleIncompleteSpecifier(Start, E - Start);<br>
+ return OptionalAmount(false);<br>
+ }<br>
+<br>
+ assert(Amt.getHowSpecified() == OptionalAmount::Constant);<br>
+<br>
+ if (*I == '$') {<br>
+ // Handle positional arguments<br>
+<br>
+ // Special case: '*0$', since this is an easy mistake.<br>
+ if (Amt.getConstantAmount() == 0) {<br>
+ H.HandleZeroPosition(Beg, I - Beg + 1);<br>
+ return OptionalAmount(false);<br>
+ }<br>
+<br>
+ const char *Tmp = Beg;<br>
+ Beg = ++I;<br>
+<br>
+ return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,<br>
+ Tmp, 0, true);<br>
+ }<br>
+<br>
+ H.HandleInvalidPosition(Beg, I - Beg, p);<br>
+ return OptionalAmount(false);<br>
+ }<br>
+<br>
+ return ParseAmount(Beg, E);<br>
+}<br>
+<br>
+<br>
+bool<br>
+clang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H,<br>
+ FormatSpecifier &CS,<br>
+ const char *Start,<br>
+ const char *&Beg, const char *E,<br>
+ unsigned *argIndex) {<br>
+ // FIXME: Support negative field widths.<br>
+ if (argIndex) {<br>
+ CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));<br>
+ }<br>
+ else {<br>
+ const OptionalAmount Amt =<br>
+ ParsePositionAmount(H, Start, Beg, E,<br>
+ analyze_format_string::FieldWidthPos);<br>
+<br>
+ if (Amt.isInvalid())<br>
+ return true;<br>
+ CS.setFieldWidth(Amt);<br>
+ }<br>
+ return false;<br>
+}<br>
+<br>
+bool<br>
+clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,<br>
+ FormatSpecifier &FS,<br>
+ const char *Start,<br>
+ const char *&Beg,<br>
+ const char *E) {<br>
+ const char *I = Beg;<br>
+<br>
+ const OptionalAmount &Amt = ParseAmount(I, E);<br>
+<br>
+ if (I == E) {<br>
+ // No more characters left?<br>
+ H.HandleIncompleteSpecifier(Start, E - Start);<br>
+ return true;<br>
+ }<br>
+<br>
+ if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {<br>
+ // Warn that positional arguments are non-standard.<br>
+ H.HandlePosition(Start, I - Start);<br>
+<br>
+ // Special case: '%0$', since this is an easy mistake.<br>
+ if (Amt.getConstantAmount() == 0) {<br>
+ H.HandleZeroPosition(Start, I - Start);<br>
+ return true;<br>
+ }<br>
+<br>
+ FS.setArgIndex(Amt.getConstantAmount() - 1);<br>
+ FS.setUsesPositionalArg();<br>
+ // Update the caller's pointer if we decided to consume<br>
+ // these characters.<br>
+ Beg = I;<br>
+ return false;<br>
+ }<br>
+<br>
+ return false;<br>
+}<br>
+<br>
+bool<br>
+clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,<br>
+ const char *&I,<br>
+ const char *E,<br>
+ const LangOptions &LO,<br>
+ bool IsScanf) {<br>
+ LengthModifier::Kind lmKind = LengthModifier::None;<br>
+ const char *lmPosition = I;<br>
+ switch (*I) {<br>
+ default:<br>
+ return false;<br>
+ case 'h':<br>
+ ++I;<br>
+ if (I != E && *I == 'h') {<br>
+ ++I;<br>
+ lmKind = LengthModifier::AsChar;<br>
+ } else {<br>
+ lmKind = LengthModifier::AsShort;<br>
+ }<br>
+ break;<br>
+ case 'l':<br>
+ ++I;<br>
+ if (I != E && *I == 'l') {<br>
+ ++I;<br>
+ lmKind = LengthModifier::AsLongLong;<br>
+ } else {<br>
+ lmKind = LengthModifier::AsLong;<br>
+ }<br>
+ break;<br>
+ case 'j': lmKind = LengthModifier::AsIntMax; ++I; break;<br>
+ case 'z': lmKind = LengthModifier::AsSizeT; ++I; break;<br>
+ case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break;<br>
+ case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;<br>
+ case 'q': lmKind = LengthModifier::AsQuad; ++I; break;<br>
+ case 'a':<br>
+ if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {<br>
+ // For scanf in C90, look at the next character to see if this should<br>
+ // be parsed as the GNU extension 'a' length modifier. If not, this<br>
+ // will be parsed as a conversion specifier.<br>
+ ++I;<br>
+ if (I != E && (*I == 's' || *I == 'S' || *I == '[')) {<br>
+ lmKind = LengthModifier::AsAllocate;<br>
+ break;<br>
+ }<br>
+ --I;<br>
+ }<br>
+ return false;<br>
+ case 'm':<br>
+ if (IsScanf) {<br>
+ lmKind = LengthModifier::AsMAllocate;<br>
+ ++I;<br>
+ break;<br>
+ }<br>
+ return false;<br>
+ // printf: AsInt64, AsInt32, AsInt3264<br>
+ // scanf: AsInt64<br>
+ case 'I':<br>
+ if (I + 1 != E && I + 2 != E) {<br>
+ if (I[1] == '6' && I[2] == '4') {<br>
+ I += 3;<br>
+ lmKind = LengthModifier::AsInt64;<br>
+ break;<br>
+ }<br>
+ if (IsScanf)<br>
+ return false;<br>
+<br>
+ if (I[1] == '3' && I[2] == '2') {<br>
+ I += 3;<br>
+ lmKind = LengthModifier::AsInt32;<br>
+ break;<br>
+ }<br>
+ }<br>
+ ++I;<br>
+ lmKind = LengthModifier::AsInt3264;<br>
+ break;<br>
+ case 'w':<br>
+ lmKind = LengthModifier::AsWide; ++I; break;<br>
+ }<br>
+ LengthModifier lm(lmPosition, lmKind);<br>
+ FS.setLengthModifier(lm);<br>
+ return true;<br>
+}<br>
+<br>
+bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(<br>
+ const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len) {<br>
+ if (SpecifierBegin + 1 >= FmtStrEnd)<br>
+ return false;<br>
+<br>
+ const llvm::UTF8 *SB =<br>
+ reinterpret_cast<const llvm::UTF8 *>(SpecifierBegin + 1);<br>
+ const llvm::UTF8 *SE = reinterpret_cast<const llvm::UTF8 *>(FmtStrEnd);<br>
+ const char FirstByte = *SB;<br>
+<br>
+ // If the invalid specifier is a multibyte UTF-8 string, return the<br>
+ // total length accordingly so that the conversion specifier can be<br>
+ // properly updated to reflect a complete UTF-8 specifier.<br>
+ unsigned NumBytes = llvm::getNumBytesForUTF8(FirstByte);<br>
+ if (NumBytes == 1)<br>
+ return false;<br>
+ if (SB + NumBytes > SE)<br>
+ return false;<br>
+<br>
+ Len = NumBytes + 1;<br>
+ return true;<br>
+}<br>
+<br>
+//===----------------------------------------------------------------------===//<br>
+// Methods on ArgType.<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+clang::analyze_format_string::ArgType::MatchKind<br>
+ArgType::matchesType(ASTContext &C, QualType argTy) const {<br>
+ if (Ptr) {<br>
+ // It has to be a pointer.<br>
+ const PointerType *PT = argTy->getAs<PointerType>();<br>
+ if (!PT)<br>
+ return NoMatch;<br>
+<br>
+ // We cannot write through a const qualified pointer.<br>
+ if (PT->getPointeeType().isConstQualified())<br>
+ return NoMatch;<br>
+<br>
+ argTy = PT->getPointeeType();<br>
+ }<br>
+<br>
+ switch (K) {<br>
+ case InvalidTy:<br>
+ llvm_unreachable("ArgType must be valid");<br>
+<br>
+ case UnknownTy:<br>
+ return Match;<br>
+<br>
+ case AnyCharTy: {<br>
+ if (const EnumType *ETy = argTy->getAs<EnumType>()) {<br>
+ // If the enum is incomplete we know nothing about the underlying type.<br>
+ // Assume that it's 'int'.<br>
+ if (!ETy->getDecl()->isComplete())<br>
+ return NoMatch;<br>
+ argTy = ETy->getDecl()->getIntegerType();<br>
+ }<br>
+<br>
+ if (const BuiltinType *BT = argTy->getAs<BuiltinType>())<br>
+ switch (BT->getKind()) {<br>
+ default:<br>
+ break;<br>
+ case BuiltinType::Char_S:<br>
+ case BuiltinType::SChar:<br>
+ case BuiltinType::UChar:<br>
+ case BuiltinType::Char_U:<br>
+ return Match;<br>
+ }<br>
+ return NoMatch;<br>
+ }<br>
+<br>
+ case SpecificTy: {<br>
+ if (const EnumType *ETy = argTy->getAs<EnumType>()) {<br>
+ // If the enum is incomplete we know nothing about the underlying type.<br>
+ // Assume that it's 'int'.<br>
+ if (!ETy->getDecl()->isComplete())<br>
+ argTy = C.IntTy;<br>
+ else<br>
+ argTy = ETy->getDecl()->getIntegerType();<br>
+ }<br>
+ argTy = C.getCanonicalType(argTy).getUnqualifiedType();<br>
+<br>
+ if (T == argTy)<br>
+ return Match;<br>
+ // Check for "compatible types".<br>
+ if (const BuiltinType *BT = argTy->getAs<BuiltinType>())<br>
+ switch (BT->getKind()) {<br>
+ default:<br>
+ break;<br>
+ case BuiltinType::Char_S:<br>
+ case BuiltinType::SChar:<br>
+ case BuiltinType::Char_U:<br>
+ case BuiltinType::UChar:<br>
+ return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match<br>
+ : NoMatch;<br>
+ case BuiltinType::Short:<br>
+ return T == C.UnsignedShortTy ? Match : NoMatch;<br>
+ case BuiltinType::UShort:<br>
+ return T == C.ShortTy ? Match : NoMatch;<br>
+ case BuiltinType::Int:<br>
+ return T == C.UnsignedIntTy ? Match : NoMatch;<br>
+ case BuiltinType::UInt:<br>
+ return T == C.IntTy ? Match : NoMatch;<br>
+ case BuiltinType::Long:<br>
+ return T == C.UnsignedLongTy ? Match : NoMatch;<br>
+ case BuiltinType::ULong:<br>
+ return T == C.LongTy ? Match : NoMatch;<br>
+ case BuiltinType::LongLong:<br>
+ return T == C.UnsignedLongLongTy ? Match : NoMatch;<br>
+ case BuiltinType::ULongLong:<br>
+ return T == C.LongLongTy ? Match : NoMatch;<br>
+ }<br>
+ return NoMatch;<br>
+ }<br>
+<br>
+ case CStrTy: {<br>
+ const PointerType *PT = argTy->getAs<PointerType>();<br>
+ if (!PT)<br>
+ return NoMatch;<br>
+ QualType pointeeTy = PT->getPointeeType();<br>
+ if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())<br>
+ switch (BT->getKind()) {<br>
+ case BuiltinType::Void:<br>
+ case BuiltinType::Char_U:<br>
+ case BuiltinType::UChar:<br>
+ case BuiltinType::Char_S:<br>
+ case BuiltinType::SChar:<br>
+ return Match;<br>
+ default:<br>
+ break;<br>
+ }<br>
+<br>
+ return NoMatch;<br>
+ }<br>
+<br>
+ case WCStrTy: {<br>
+ const PointerType *PT = argTy->getAs<PointerType>();<br>
+ if (!PT)<br>
+ return NoMatch;<br>
+ QualType pointeeTy =<br>
+ C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();<br>
+ return pointeeTy == C.getWideCharType() ? Match : NoMatch;<br>
+ }<br>
+<br>
+ case WIntTy: {<br>
+ QualType WInt = C.getCanonicalType(C.getWIntType()).getUnqualifiedType();<br>
+<br>
+ if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt)<br>
+ return Match;<br>
+<br>
+ QualType PromoArg = argTy->isPromotableIntegerType()<br>
+ ? C.getPromotedIntegerType(argTy)<br>
+ : argTy;<br>
+ PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();<br>
+<br>
+ // If the promoted argument is the corresponding signed type of the<br>
+ // wint_t type, then it should match.<br>
+ if (PromoArg->hasSignedIntegerRepresentation() &&<br>
+ C.getCorrespondingUnsignedType(PromoArg) == WInt)<br>
+ return Match;<br>
+<br>
+ return WInt == PromoArg ? Match : NoMatch;<br>
+ }<br>
+<br>
+ case CPointerTy:<br>
+ if (argTy->isVoidPointerType()) {<br>
+ return Match;<br>
+ } if (argTy->isPointerType() || argTy->isObjCObjectPointerType() ||<br>
+ argTy->isBlockPointerType() || argTy->isNullPtrType()) {<br>
+ return NoMatchPedantic;<br>
+ } else {<br>
+ return NoMatch;<br>
+ }<br>
+<br>
+ case ObjCPointerTy: {<br>
+ if (argTy->getAs<ObjCObjectPointerType>() ||<br>
+ argTy->getAs<BlockPointerType>())<br>
+ return Match;<br>
+<br>
+ // Handle implicit toll-free bridging.<br>
+ if (const PointerType *PT = argTy->getAs<PointerType>()) {<br>
+ // Things such as CFTypeRef are really just opaque pointers<br>
+ // to C structs representing CF types that can often be bridged<br>
+ // to Objective-C objects. Since the compiler doesn't know which<br>
+ // structs can be toll-free bridged, we just accept them all.<br>
+ QualType pointee = PT->getPointeeType();<br>
+ if (pointee->getAsStructureType() || pointee->isVoidType())<br>
+ return Match;<br>
+ }<br>
+ return NoMatch;<br>
+ }<br>
+ }<br>
+<br>
+ llvm_unreachable("Invalid ArgType Kind!");<br>
+}<br>
+<br>
+QualType ArgType::getRepresentativeType(ASTContext &C) const {<br>
+ QualType Res;<br>
+ switch (K) {<br>
+ case InvalidTy:<br>
+ llvm_unreachable("No representative type for Invalid ArgType");<br>
+ case UnknownTy:<br>
+ llvm_unreachable("No representative type for Unknown ArgType");<br>
+ case AnyCharTy:<br>
+ Res = C.CharTy;<br>
+ break;<br>
+ case SpecificTy:<br>
+ Res = T;<br>
+ break;<br>
+ case CStrTy:<br>
+ Res = C.getPointerType(C.CharTy);<br>
+ break;<br>
+ case WCStrTy:<br>
+ Res = C.getPointerType(C.getWideCharType());<br>
+ break;<br>
+ case ObjCPointerTy:<br>
+ Res = C.ObjCBuiltinIdTy;<br>
+ break;<br>
+ case CPointerTy:<br>
+ Res = C.VoidPtrTy;<br>
+ break;<br>
+ case WIntTy: {<br>
+ Res = C.getWIntType();<br>
+ break;<br>
+ }<br>
+ }<br>
+<br>
+ if (Ptr)<br>
+ Res = C.getPointerType(Res);<br>
+ return Res;<br>
+}<br>
+<br>
+std::string ArgType::getRepresentativeTypeName(ASTContext &C) const {<br>
+ std::string S = getRepresentativeType(C).getAsString();<br>
+<br>
+ std::string Alias;<br>
+ if (Name) {<br>
+ // Use a specific name for this type, e.g. "size_t".<br>
+ Alias = Name;<br>
+ if (Ptr) {<br>
+ // If ArgType is actually a pointer to T, append an asterisk.<br>
+ Alias += (Alias[Alias.size()-1] == '*') ? "*" : " *";<br>
+ }<br>
+ // If Alias is the same as the underlying type, e.g. wchar_t, then drop it.<br>
+ if (S == Alias)<br>
+ Alias.clear();<br>
+ }<br>
+<br>
+ if (!Alias.empty())<br>
+ return std::string("'") + Alias + "' (aka '" + S + "')";<br>
+ return std::string("'") + S + "'";<br>
+}<br>
+<br>
+<br>
+//===----------------------------------------------------------------------===//<br>
+// Methods on OptionalAmount.<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+ArgType<br>
+analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const {<br>
+ return Ctx.IntTy;<br>
+}<br>
+<br>
+//===----------------------------------------------------------------------===//<br>
+// Methods on LengthModifier.<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+const char *<br>
+analyze_format_string::LengthModifier::toString() const {<br>
+ switch (kind) {<br>
+ case AsChar:<br>
+ return "hh";<br>
+ case AsShort:<br>
+ return "h";<br>
+ case AsLong: // or AsWideChar<br>
+ return "l";<br>
+ case AsLongLong:<br>
+ return "ll";<br>
+ case AsQuad:<br>
+ return "q";<br>
+ case AsIntMax:<br>
+ return "j";<br>
+ case AsSizeT:<br>
+ return "z";<br>
+ case AsPtrDiff:<br>
+ return "t";<br>
+ case AsInt32:<br>
+ return "I32";<br>
+ case AsInt3264:<br>
+ return "I";<br>
+ case AsInt64:<br>
+ return "I64";<br>
+ case AsLongDouble:<br>
+ return "L";<br>
+ case AsAllocate:<br>
+ return "a";<br>
+ case AsMAllocate:<br>
+ return "m";<br>
+ case AsWide:<br>
+ return "w";<br>
+ case None:<br>
+ return "";<br>
+ }<br>
+ return nullptr;<br>
+}<br>
+<br>
+//===----------------------------------------------------------------------===//<br>
+// Methods on ConversionSpecifier.<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+const char *ConversionSpecifier::toString() const {<br>
+ switch (kind) {<br>
+ case dArg: return "d";<br>
+ case DArg: return "D";<br>
+ case iArg: return "i";<br>
+ case oArg: return "o";<br>
+ case OArg: return "O";<br>
+ case uArg: return "u";<br>
+ case UArg: return "U";<br>
+ case xArg: return "x";<br>
+ case XArg: return "X";<br>
+ case fArg: return "f";<br>
+ case FArg: return "F";<br>
+ case eArg: return "e";<br>
+ case EArg: return "E";<br>
+ case gArg: return "g";<br>
+ case GArg: return "G";<br>
+ case aArg: return "a";<br>
+ case AArg: return "A";<br>
+ case cArg: return "c";<br>
+ case sArg: return "s";<br>
+ case pArg: return "p";<br>
+ case PArg:<br>
+ return "P";<br>
+ case nArg: return "n";<br>
+ case PercentArg: return "%";<br>
+ case ScanListArg: return "[";<br>
+ case InvalidSpecifier: return nullptr;<br>
+<br>
+ // POSIX unicode extensions.<br>
+ case CArg: return "C";<br>
+ case SArg: return "S";<br>
+<br>
+ // Objective-C specific specifiers.<br>
+ case ObjCObjArg: return "@";<br>
+<br>
+ // FreeBSD kernel specific specifiers.<br>
+ case FreeBSDbArg: return "b";<br>
+ case FreeBSDDArg: return "D";<br>
+ case FreeBSDrArg: return "r";<br>
+ case FreeBSDyArg: return "y";<br>
+<br>
+ // GlibC specific specifiers.<br>
+ case PrintErrno: return "m";<br>
+<br>
+ // MS specific specifiers.<br>
+ case ZArg: return "Z";<br>
+ }<br>
+ return nullptr;<br>
+}<br>
+<br>
+Optional<ConversionSpecifier><br>
+ConversionSpecifier::getStandardSpecifier() const {<br>
+ ConversionSpecifier::Kind NewKind;<br>
+<br>
+ switch (getKind()) {<br>
+ default:<br>
+ return None;<br>
+ case DArg:<br>
+ NewKind = dArg;<br>
+ break;<br>
+ case UArg:<br>
+ NewKind = uArg;<br>
+ break;<br>
+ case OArg:<br>
+ NewKind = oArg;<br>
+ break;<br>
+ }<br>
+<br>
+ ConversionSpecifier FixedCS(*this);<br>
+ FixedCS.setKind(NewKind);<br>
+ return FixedCS;<br>
+}<br>
+<br>
+//===----------------------------------------------------------------------===//<br>
+// Methods on OptionalAmount.<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+void OptionalAmount::toString(raw_ostream &os) const {<br>
+ switch (hs) {<br>
+ case Invalid:<br>
+ case NotSpecified:<br>
+ return;<br>
+ case Arg:<br>
+ if (UsesDotPrefix)<br>
+ os << ".";<br>
+ if (usesPositionalArg())<br>
+ os << "*" << getPositionalArgIndex() << "$";<br>
+ else<br>
+ os << "*";<br>
+ break;<br>
+ case Constant:<br>
+ if (UsesDotPrefix)<br>
+ os << ".";<br>
+ os << amt;<br>
+ break;<br>
+ }<br>
+}<br>
+<br>
+bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {<br>
+ switch (LM.getKind()) {<br>
+ case LengthModifier::None:<br>
+ return true;<br>
+<br>
+ // Handle most integer flags<br>
+ case LengthModifier::AsShort:<br>
+ if (Target.getTriple().isOSMSVCRT()) {<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::cArg:<br>
+ case ConversionSpecifier::CArg:<br>
+ case ConversionSpecifier::sArg:<br>
+ case ConversionSpecifier::SArg:<br>
+ case ConversionSpecifier::ZArg:<br>
+ return true;<br>
+ default:<br>
+ break;<br>
+ }<br>
+ }<br>
+ LLVM_FALLTHROUGH;<br>
+ case LengthModifier::AsChar:<br>
+ case LengthModifier::AsLongLong:<br>
+ case LengthModifier::AsQuad:<br>
+ case LengthModifier::AsIntMax:<br>
+ case LengthModifier::AsSizeT:<br>
+ case LengthModifier::AsPtrDiff:<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::dArg:<br>
+ case ConversionSpecifier::DArg:<br>
+ case ConversionSpecifier::iArg:<br>
+ case ConversionSpecifier::oArg:<br>
+ case ConversionSpecifier::OArg:<br>
+ case ConversionSpecifier::uArg:<br>
+ case ConversionSpecifier::UArg:<br>
+ case ConversionSpecifier::xArg:<br>
+ case ConversionSpecifier::XArg:<br>
+ case ConversionSpecifier::nArg:<br>
+ return true;<br>
+ case ConversionSpecifier::FreeBSDrArg:<br>
+ case ConversionSpecifier::FreeBSDyArg:<br>
+ return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS4();<br>
+ default:<br>
+ return false;<br>
+ }<br>
+<br>
+ // Handle 'l' flag<br>
+ case LengthModifier::AsLong: // or AsWideChar<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::dArg:<br>
+ case ConversionSpecifier::DArg:<br>
+ case ConversionSpecifier::iArg:<br>
+ case ConversionSpecifier::oArg:<br>
+ case ConversionSpecifier::OArg:<br>
+ case ConversionSpecifier::uArg:<br>
+ case ConversionSpecifier::UArg:<br>
+ case ConversionSpecifier::xArg:<br>
+ case ConversionSpecifier::XArg:<br>
+ case ConversionSpecifier::aArg:<br>
+ case ConversionSpecifier::AArg:<br>
+ case ConversionSpecifier::fArg:<br>
+ case ConversionSpecifier::FArg:<br>
+ case ConversionSpecifier::eArg:<br>
+ case ConversionSpecifier::EArg:<br>
+ case ConversionSpecifier::gArg:<br>
+ case ConversionSpecifier::GArg:<br>
+ case ConversionSpecifier::nArg:<br>
+ case ConversionSpecifier::cArg:<br>
+ case ConversionSpecifier::sArg:<br>
+ case ConversionSpecifier::ScanListArg:<br>
+ case ConversionSpecifier::ZArg:<br>
+ return true;<br>
+ case ConversionSpecifier::FreeBSDrArg:<br>
+ case ConversionSpecifier::FreeBSDyArg:<br>
+ return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS4();<br>
+ default:<br>
+ return false;<br>
+ }<br>
+<br>
+ case LengthModifier::AsLongDouble:<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::aArg:<br>
+ case ConversionSpecifier::AArg:<br>
+ case ConversionSpecifier::fArg:<br>
+ case ConversionSpecifier::FArg:<br>
+ case ConversionSpecifier::eArg:<br>
+ case ConversionSpecifier::EArg:<br>
+ case ConversionSpecifier::gArg:<br>
+ case ConversionSpecifier::GArg:<br>
+ return true;<br>
+ // GNU libc extension.<br>
+ case ConversionSpecifier::dArg:<br>
+ case ConversionSpecifier::iArg:<br>
+ case ConversionSpecifier::oArg:<br>
+ case ConversionSpecifier::uArg:<br>
+ case ConversionSpecifier::xArg:<br>
+ case ConversionSpecifier::XArg:<br>
+ return !Target.getTriple().isOSDarwin() &&<br>
+ !Target.getTriple().isOSWindows();<br>
+ default:<br>
+ return false;<br>
+ }<br>
+<br>
+ case LengthModifier::AsAllocate:<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::sArg:<br>
+ case ConversionSpecifier::SArg:<br>
+ case ConversionSpecifier::ScanListArg:<br>
+ return true;<br>
+ default:<br>
+ return false;<br>
+ }<br>
+<br>
+ case LengthModifier::AsMAllocate:<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::cArg:<br>
+ case ConversionSpecifier::CArg:<br>
+ case ConversionSpecifier::sArg:<br>
+ case ConversionSpecifier::SArg:<br>
+ case ConversionSpecifier::ScanListArg:<br>
+ return true;<br>
+ default:<br>
+ return false;<br>
+ }<br>
+ case LengthModifier::AsInt32:<br>
+ case LengthModifier::AsInt3264:<br>
+ case LengthModifier::AsInt64:<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::dArg:<br>
+ case ConversionSpecifier::iArg:<br>
+ case ConversionSpecifier::oArg:<br>
+ case ConversionSpecifier::uArg:<br>
+ case ConversionSpecifier::xArg:<br>
+ case ConversionSpecifier::XArg:<br>
+ return Target.getTriple().isOSMSVCRT();<br>
+ default:<br>
+ return false;<br>
+ }<br>
+ case LengthModifier::AsWide:<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::cArg:<br>
+ case ConversionSpecifier::CArg:<br>
+ case ConversionSpecifier::sArg:<br>
+ case ConversionSpecifier::SArg:<br>
+ case ConversionSpecifier::ZArg:<br>
+ return Target.getTriple().isOSMSVCRT();<br>
+ default:<br>
+ return false;<br>
+ }<br>
+ }<br>
+ llvm_unreachable("Invalid LengthModifier Kind!");<br>
+}<br>
+<br>
+bool FormatSpecifier::hasStandardLengthModifier() const {<br>
+ switch (LM.getKind()) {<br>
+ case LengthModifier::None:<br>
+ case LengthModifier::AsChar:<br>
+ case LengthModifier::AsShort:<br>
+ case LengthModifier::AsLong:<br>
+ case LengthModifier::AsLongLong:<br>
+ case LengthModifier::AsIntMax:<br>
+ case LengthModifier::AsSizeT:<br>
+ case LengthModifier::AsPtrDiff:<br>
+ case LengthModifier::AsLongDouble:<br>
+ return true;<br>
+ case LengthModifier::AsAllocate:<br>
+ case LengthModifier::AsMAllocate:<br>
+ case LengthModifier::AsQuad:<br>
+ case LengthModifier::AsInt32:<br>
+ case LengthModifier::AsInt3264:<br>
+ case LengthModifier::AsInt64:<br>
+ case LengthModifier::AsWide:<br>
+ return false;<br>
+ }<br>
+ llvm_unreachable("Invalid LengthModifier Kind!");<br>
+}<br>
+<br>
+bool FormatSpecifier::hasStandardConversionSpecifier(<br>
+ const LangOptions &LangOpt) const {<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::cArg:<br>
+ case ConversionSpecifier::dArg:<br>
+ case ConversionSpecifier::iArg:<br>
+ case ConversionSpecifier::oArg:<br>
+ case ConversionSpecifier::uArg:<br>
+ case ConversionSpecifier::xArg:<br>
+ case ConversionSpecifier::XArg:<br>
+ case ConversionSpecifier::fArg:<br>
+ case ConversionSpecifier::FArg:<br>
+ case ConversionSpecifier::eArg:<br>
+ case ConversionSpecifier::EArg:<br>
+ case ConversionSpecifier::gArg:<br>
+ case ConversionSpecifier::GArg:<br>
+ case ConversionSpecifier::aArg:<br>
+ case ConversionSpecifier::AArg:<br>
+ case ConversionSpecifier::sArg:<br>
+ case ConversionSpecifier::pArg:<br>
+ case ConversionSpecifier::nArg:<br>
+ case ConversionSpecifier::ObjCObjArg:<br>
+ case ConversionSpecifier::ScanListArg:<br>
+ case ConversionSpecifier::PercentArg:<br>
+ case ConversionSpecifier::PArg:<br>
+ return true;<br>
+ case ConversionSpecifier::CArg:<br>
+ case ConversionSpecifier::SArg:<br>
+ return LangOpt.ObjC;<br>
+ case ConversionSpecifier::InvalidSpecifier:<br>
+ case ConversionSpecifier::FreeBSDbArg:<br>
+ case ConversionSpecifier::FreeBSDDArg:<br>
+ case ConversionSpecifier::FreeBSDrArg:<br>
+ case ConversionSpecifier::FreeBSDyArg:<br>
+ case ConversionSpecifier::PrintErrno:<br>
+ case ConversionSpecifier::DArg:<br>
+ case ConversionSpecifier::OArg:<br>
+ case ConversionSpecifier::UArg:<br>
+ case ConversionSpecifier::ZArg:<br>
+ return false;<br>
+ }<br>
+ llvm_unreachable("Invalid ConversionSpecifier Kind!");<br>
+}<br>
+<br>
+bool FormatSpecifier::hasStandardLengthConversionCombination() const {<br>
+ if (LM.getKind() == LengthModifier::AsLongDouble) {<br>
+ switch(CS.getKind()) {<br>
+ case ConversionSpecifier::dArg:<br>
+ case ConversionSpecifier::iArg:<br>
+ case ConversionSpecifier::oArg:<br>
+ case ConversionSpecifier::uArg:<br>
+ case ConversionSpecifier::xArg:<br>
+ case ConversionSpecifier::XArg:<br>
+ return false;<br>
+ default:<br>
+ return true;<br>
+ }<br>
+ }<br>
+ return true;<br>
+}<br>
+<br>
+Optional<LengthModifier> FormatSpecifier::getCorrectedLengthModifier() const {<br>
+ if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {<br>
+ if (LM.getKind() == LengthModifier::AsLongDouble ||<br>
+ LM.getKind() == LengthModifier::AsQuad) {<br>
+ LengthModifier FixedLM(LM);<br>
+ FixedLM.setKind(LengthModifier::AsLongLong);<br>
+ return FixedLM;<br>
+ }<br>
+ }<br>
+<br>
+ return None;<br>
+}<br>
+<br>
+bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,<br>
+ LengthModifier &LM) {<br>
+ assert(isa<TypedefType>(QT) && "Expected a TypedefType");<br>
+ const TypedefNameDecl *Typedef = cast<TypedefType>(QT)->getDecl();<br>
+<br>
+ for (;;) {<br>
+ const IdentifierInfo *Identifier = Typedef->getIdentifier();<br>
+ if (Identifier->getName() == "size_t") {<br>
+ LM.setKind(LengthModifier::AsSizeT);<br>
+ return true;<br>
+ } else if (Identifier->getName() == "ssize_t") {<br>
+ // Not C99, but common in Unix.<br>
+ LM.setKind(LengthModifier::AsSizeT);<br>
+ return true;<br>
+ } else if (Identifier->getName() == "intmax_t") {<br>
+ LM.setKind(LengthModifier::AsIntMax);<br>
+ return true;<br>
+ } else if (Identifier->getName() == "uintmax_t") {<br>
+ LM.setKind(LengthModifier::AsIntMax);<br>
+ return true;<br>
+ } else if (Identifier->getName() == "ptrdiff_t") {<br>
+ LM.setKind(LengthModifier::AsPtrDiff);<br>
+ return true;<br>
+ }<br>
+<br>
+ QualType T = Typedef->getUnderlyingType();<br>
+ if (!isa<TypedefType>(T))<br>
+ break;<br>
+<br>
+ Typedef = cast<TypedefType>(T)->getDecl();<br>
+ }<br>
+ return false;<br>
+}<br>
<br>
Added: cfe/trunk/lib/AST/FormatStringParsing.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/FormatStringParsing.h?rev=345971&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/FormatStringParsing.h?rev=345971&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/FormatStringParsing.h (added)<br>
+++ cfe/trunk/lib/AST/FormatStringParsing.h Fri Nov 2 06:14:11 2018<br>
@@ -0,0 +1,79 @@<br>
+#ifndef LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H<br>
+#define LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H<br>
+<br>
+#include "clang/AST/ASTContext.h"<br>
+#include "clang/AST/Type.h"<br>
+#include "clang/AST/FormatString.h"<br>
+<br>
+namespace clang {<br>
+<br>
+class LangOptions;<br>
+<br>
+template <typename T><br>
+class UpdateOnReturn {<br>
+ T &ValueToUpdate;<br>
+ const T &ValueToCopy;<br>
+public:<br>
+ UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)<br>
+ : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}<br>
+<br>
+ ~UpdateOnReturn() {<br>
+ ValueToUpdate = ValueToCopy;<br>
+ }<br>
+};<br>
+<br>
+namespace analyze_format_string {<br>
+<br>
+OptionalAmount ParseAmount(const char *&Beg, const char *E);<br>
+OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,<br>
+ unsigned &argIndex);<br>
+<br>
+OptionalAmount ParsePositionAmount(FormatStringHandler &H,<br>
+ const char *Start, const char *&Beg,<br>
+ const char *E, PositionContext p);<br>
+<br>
+bool ParseFieldWidth(FormatStringHandler &H,<br>
+ FormatSpecifier &CS,<br>
+ const char *Start, const char *&Beg, const char *E,<br>
+ unsigned *argIndex);<br>
+<br>
+bool ParseArgPosition(FormatStringHandler &H,<br>
+ FormatSpecifier &CS, const char *Start,<br>
+ const char *&Beg, const char *E);<br>
+<br>
+/// Returns true if a LengthModifier was parsed and installed in the<br>
+/// FormatSpecifier& argument, and false otherwise.<br>
+bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const char *E,<br>
+ const LangOptions &LO, bool IsScanf = false);<br>
+<br>
+/// Returns true if the invalid specifier in \p SpecifierBegin is a UTF-8<br>
+/// string; check that it won't go further than \p FmtStrEnd and write<br>
+/// up the total size in \p Len.<br>
+bool ParseUTF8InvalidSpecifier(const char *SpecifierBegin,<br>
+ const char *FmtStrEnd, unsigned &Len);<br>
+<br>
+template <typename T> class SpecifierResult {<br>
+ T FS;<br>
+ const char *Start;<br>
+ bool Stop;<br>
+public:<br>
+ SpecifierResult(bool stop = false)<br>
+ : Start(nullptr), Stop(stop) {}<br>
+ SpecifierResult(const char *start,<br>
+ const T &fs)<br>
+ : FS(fs), Start(start), Stop(false) {}<br>
+<br>
+ const char *getStart() const { return Start; }<br>
+ bool shouldStop() const { return Stop; }<br>
+ bool hasValue() const { return Start != nullptr; }<br>
+ const T &getValue() const {<br>
+ assert(hasValue());<br>
+ return FS;<br>
+ }<br>
+ const T &getValue() { return FS; }<br>
+};<br>
+<br>
+} // end analyze_format_string namespace<br>
+} // end clang namespace<br>
+<br>
+#endif<br>
<br>
Added: cfe/trunk/lib/AST/OSLog.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/OSLog.cpp?rev=345971&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/OSLog.cpp?rev=345971&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/OSLog.cpp (added)<br>
+++ cfe/trunk/lib/AST/OSLog.cpp Fri Nov 2 06:14:11 2018<br>
@@ -0,0 +1,203 @@<br>
+// TODO: header template<br>
+<br>
+#include "clang/AST/OSLog.h"<br>
+#include "clang/AST/Attr.h"<br>
+#include "clang/AST/Decl.h"<br>
+#include "clang/AST/DeclCXX.h"<br>
+#include "clang/AST/ExprObjC.h"<br>
+#include "clang/AST/FormatString.h"<br>
+#include "clang/Basic/Builtins.h"<br>
+#include "llvm/ADT/SmallBitVector.h"<br>
+<br>
+using namespace clang;<br>
+<br>
+using clang::analyze_os_log::OSLogBufferItem;<br>
+using clang::analyze_os_log::OSLogBufferLayout;<br>
+<br>
+namespace {<br>
+class OSLogFormatStringHandler<br>
+ : public analyze_format_string::FormatStringHandler {<br>
+private:<br>
+ struct ArgData {<br>
+ const Expr *E = nullptr;<br>
+ Optional<OSLogBufferItem::Kind> Kind;<br>
+ Optional<unsigned> Size;<br>
+ Optional<const Expr *> Count;<br>
+ Optional<const Expr *> Precision;<br>
+ Optional<const Expr *> FieldWidth;<br>
+ unsigned char Flags = 0;<br>
+ };<br>
+ SmallVector<ArgData, 4> ArgsData;<br>
+ ArrayRef<const Expr *> Args;<br>
+<br>
+ OSLogBufferItem::Kind<br>
+ getKind(analyze_format_string::ConversionSpecifier::Kind K) {<br>
+ switch (K) {<br>
+ case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s"<br>
+ return OSLogBufferItem::StringKind;<br>
+ case clang::analyze_format_string::ConversionSpecifier::SArg: // "%S"<br>
+ return OSLogBufferItem::WideStringKind;<br>
+ case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"<br>
+ return OSLogBufferItem::PointerKind;<br>
+ case clang::analyze_format_string::ConversionSpecifier::ObjCObjArg: // "%@"<br>
+ return OSLogBufferItem::ObjCObjKind;<br>
+ case clang::analyze_format_string::ConversionSpecifier::PrintErrno: // "%m"<br>
+ return OSLogBufferItem::ErrnoKind;<br>
+ default:<br>
+ return OSLogBufferItem::ScalarKind;<br>
+ }<br>
+ }<br>
+ }<br>
+<br>
+public:<br>
+ OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) {<br>
+ ArgsData.reserve(Args.size());<br>
+ }<br>
+<br>
+ virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,<br>
+ const char *StartSpecifier,<br>
+ unsigned SpecifierLen) {<br>
+ if (!FS.consumesDataArgument() &&<br>
+ FS.getConversionSpecifier().getKind() !=<br>
+ clang::analyze_format_string::ConversionSpecifier::PrintErrno)<br>
+ return true;<br>
+<br>
+ ArgsData.emplace_back();<br>
+ unsigned ArgIndex = FS.getArgIndex();<br>
+ if (ArgIndex < Args.size())<br>
+ ArgsData.back().E = Args[ArgIndex];<br>
+<br>
+ // First get the Kind<br>
+ ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind());<br>
+ if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind &&<br>
+ !ArgsData.back().E) {<br>
+ // missing argument<br>
+ ArgsData.pop_back();<br>
+ return false;<br>
+ }<br>
+<br>
+ switch (FS.getConversionSpecifier().getKind()) {<br>
+ case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s"<br>
+ case clang::analyze_format_string::ConversionSpecifier::SArg: { // "%S"<br>
+ auto &precision = FS.getPrecision();<br>
+ switch (precision.getHowSpecified()) {<br>
+ case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%s"<br>
+ break;<br>
+ case clang::analyze_format_string::OptionalAmount::Constant: // "%.16s"<br>
+ ArgsData.back().Size = precision.getConstantAmount();<br>
+ break;<br>
+ case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s"<br>
+ ArgsData.back().Count = Args[precision.getArgIndex()];<br>
+ break;<br>
+ case clang::analyze_format_string::OptionalAmount::Invalid:<br>
+ return false;<br>
+ }<br>
+ break;<br>
+ }<br>
+ case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"<br>
+ auto &precision = FS.getPrecision();<br>
+ switch (precision.getHowSpecified()) {<br>
+ case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%P"<br>
+ return false; // length must be supplied with pointer format specifier<br>
+ case clang::analyze_format_string::OptionalAmount::Constant: // "%.16P"<br>
+ ArgsData.back().Size = precision.getConstantAmount();<br>
+ break;<br>
+ case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P"<br>
+ ArgsData.back().Count = Args[precision.getArgIndex()];<br>
+ break;<br>
+ case clang::analyze_format_string::OptionalAmount::Invalid:<br>
+ return false;<br>
+ }<br>
+ break;<br>
+ }<br>
+ default:<br>
+ if (FS.getPrecision().hasDataArgument()) {<br>
+ ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];<br>
+ }<br>
+ break;<br>
+ }<br>
+ if (FS.getFieldWidth().hasDataArgument()) {<br>
+ ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];<br>
+ }<br>
+<br>
+ if (FS.isPrivate()) {<br>
+ ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;<br>
+ }<br>
+ if (FS.isPublic()) {<br>
+ ArgsData.back().Flags |= OSLogBufferItem::IsPublic;<br>
+ }<br>
+ return true;<br>
+ }<br>
+<br>
+ void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {<br>
+ Layout.Items.clear();<br>
+ for (auto &Data : ArgsData) {<br>
+ if (Data.FieldWidth) {<br>
+ CharUnits Size = Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType());<br>
+ Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.FieldWidth,<br>
+ Size, 0);<br>
+ }<br>
+ if (Data.Precision) {<br>
+ CharUnits Size = Ctx.getTypeSizeInChars((*Data.Precision)->getType());<br>
+ Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.Precision,<br>
+ Size, 0);<br>
+ }<br>
+ if (Data.Count) {<br>
+ // "%.*P" has an extra "count" that we insert before the argument.<br>
+ CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType());<br>
+ Layout.Items.emplace_back(OSLogBufferItem::CountKind, *Data.Count, Size,<br>
+ 0);<br>
+ }<br>
+ if (Data.Size)<br>
+ Layout.Items.emplace_back(Ctx, CharUnits::fromQuantity(*Data.Size),<br>
+ Data.Flags);<br>
+ if (Data.Kind) {<br>
+ CharUnits Size;<br>
+ if (*Data.Kind == OSLogBufferItem::ErrnoKind)<br>
+ Size = CharUnits::Zero();<br>
+ else<br>
+ Size = Ctx.getTypeSizeInChars(Data.E->getType());<br>
+ Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags);<br>
+ } else {<br>
+ auto Size = Ctx.getTypeSizeInChars(Data.E->getType());<br>
+ Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E, Size,<br>
+ Data.Flags);<br>
+ }<br>
+ }<br>
+ }<br>
+};<br>
+} // end anonymous namespace<br>
+<br>
+bool clang::analyze_os_log::computeOSLogBufferLayout(<br>
+ ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {<br>
+ ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() + E->getNumArgs());<br>
+<br>
+ const Expr *StringArg;<br>
+ ArrayRef<const Expr *> VarArgs;<br>
+ switch (E->getBuiltinCallee()) {<br>
+ case Builtin::BI__builtin_os_log_format_buffer_size:<br>
+ assert(E->getNumArgs() >= 1 &&<br>
+ "__builtin_os_log_format_buffer_size takes at least 1 argument");<br>
+ StringArg = E->getArg(0);<br>
+ VarArgs = Args.slice(1);<br>
+ break;<br>
+ case Builtin::BI__builtin_os_log_format:<br>
+ assert(E->getNumArgs() >= 2 &&<br>
+ "__builtin_os_log_format takes at least 2 arguments");<br>
+ StringArg = E->getArg(1);<br>
+ VarArgs = Args.slice(2);<br>
+ break;<br>
+ default:<br>
+ llvm_unreachable("non-os_log builtin passed to computeOSLogBufferLayout");<br>
+ }<br>
+<br>
+ const StringLiteral *Lit = cast<StringLiteral>(StringArg->IgnoreParenCasts());<br>
+ assert(Lit && (Lit->isAscii() || Lit->isUTF8()));<br>
+ StringRef Data = Lit->getString();<br>
+ OSLogFormatStringHandler H(VarArgs);<br>
+ ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(),<br>
+ Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false);<br>
+<br>
+ H.computeLayout(Ctx, Layout);<br>
+ return true;<br>
+}<br>
<br>
Added: cfe/trunk/lib/AST/PrintfFormatString.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/PrintfFormatString.cpp?rev=345971&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/PrintfFormatString.cpp?rev=345971&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/PrintfFormatString.cpp (added)<br>
+++ cfe/trunk/lib/AST/PrintfFormatString.cpp Fri Nov 2 06:14:11 2018<br>
@@ -0,0 +1,1029 @@<br>
+//== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+// Handling of format string in printf and friends. The structure of format<br>
+// strings for fprintf() are described in C99 7.19.6.1.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "clang/AST/FormatString.h"<br>
+#include "clang/AST/OSLog.h"<br>
+#include "FormatStringParsing.h"<br>
+#include "clang/Basic/TargetInfo.h"<br>
+<br>
+using clang::analyze_format_string::ArgType;<br>
+using clang::analyze_format_string::FormatStringHandler;<br>
+using clang::analyze_format_string::LengthModifier;<br>
+using clang::analyze_format_string::OptionalAmount;<br>
+using clang::analyze_format_string::ConversionSpecifier;<br>
+using clang::analyze_printf::PrintfSpecifier;<br>
+<br>
+using namespace clang;<br>
+<br>
+typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier><br>
+ PrintfSpecifierResult;<br>
+<br>
+//===----------------------------------------------------------------------===//<br>
+// Methods for parsing format strings.<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+using analyze_format_string::ParseNonPositionAmount;<br>
+<br>
+static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,<br>
+ const char *Start, const char *&Beg, const char *E,<br>
+ unsigned *argIndex) {<br>
+ if (argIndex) {<br>
+ FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));<br>
+ } else {<br>
+ const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,<br>
+ analyze_format_string::PrecisionPos);<br>
+ if (Amt.isInvalid())<br>
+ return true;<br>
+ FS.setPrecision(Amt);<br>
+ }<br>
+ return false;<br>
+}<br>
+<br>
+static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS,<br>
+ const char *FlagBeg, const char *E, bool Warn) {<br>
+ StringRef Flag(FlagBeg, E - FlagBeg);<br>
+ // Currently there is only one flag.<br>
+ if (Flag == "tt") {<br>
+ FS.setHasObjCTechnicalTerm(FlagBeg);<br>
+ return false;<br>
+ }<br>
+ // Handle either the case of no flag or an invalid flag.<br>
+ if (Warn) {<br>
+ if (Flag == "")<br>
+ H.HandleEmptyObjCModifierFlag(FlagBeg, E - FlagBeg);<br>
+ else<br>
+ H.HandleInvalidObjCModifierFlag(FlagBeg, E - FlagBeg);<br>
+ }<br>
+ return true;<br>
+}<br>
+<br>
+static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,<br>
+ const char *&Beg,<br>
+ const char *E,<br>
+ unsigned &argIndex,<br>
+ const LangOptions &LO,<br>
+ const TargetInfo &Target,<br>
+ bool Warn,<br>
+ bool isFreeBSDKPrintf) {<br>
+<br>
+ using namespace clang::analyze_format_string;<br>
+ using namespace clang::analyze_printf;<br>
+<br>
+ const char *I = Beg;<br>
+ const char *Start = nullptr;<br>
+ UpdateOnReturn <const char*> UpdateBeg(Beg, I);<br>
+<br>
+ // Look for a '%' character that indicates the start of a format specifier.<br>
+ for ( ; I != E ; ++I) {<br>
+ char c = *I;<br>
+ if (c == '\0') {<br>
+ // Detect spurious null characters, which are likely errors.<br>
+ H.HandleNullChar(I);<br>
+ return true;<br>
+ }<br>
+ if (c == '%') {<br>
+ Start = I++; // Record the start of the format specifier.<br>
+ break;<br>
+ }<br>
+ }<br>
+<br>
+ // No format specifier found?<br>
+ if (!Start)<br>
+ return false;<br>
+<br>
+ if (I == E) {<br>
+ // No more characters left?<br>
+ if (Warn)<br>
+ H.HandleIncompleteSpecifier(Start, E - Start);<br>
+ return true;<br>
+ }<br>
+<br>
+ PrintfSpecifier FS;<br>
+ if (ParseArgPosition(H, FS, Start, I, E))<br>
+ return true;<br>
+<br>
+ if (I == E) {<br>
+ // No more characters left?<br>
+ if (Warn)<br>
+ H.HandleIncompleteSpecifier(Start, E - Start);<br>
+ return true;<br>
+ }<br>
+<br>
+ if (*I == '{') {<br>
+ ++I;<br>
+ unsigned char PrivacyFlags = 0;<br>
+ StringRef MatchedStr;<br>
+<br>
+ do {<br>
+ StringRef Str(I, E - I);<br>
+ std::string Match = "^[\t\n\v\f\r ]*(private|public)[\t\n\v\f\r ]*(,|})";<br>
+ llvm::Regex R(Match);<br>
+ SmallVector<StringRef, 2> Matches;<br>
+<br>
+ if (R.match(Str, &Matches)) {<br>
+ MatchedStr = Matches[1];<br>
+ I += Matches[0].size();<br>
+<br>
+ // Set the privacy flag if the privacy annotation in the<br>
+ // comma-delimited segment is at least as strict as the privacy<br>
+ // annotations in previous comma-delimited segments.<br>
+ if (MatchedStr.equals("private"))<br>
+ PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate;<br>
+ else if (PrivacyFlags == 0 && MatchedStr.equals("public"))<br>
+ PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic;<br>
+ } else {<br>
+ size_t CommaOrBracePos =<br>
+ Str.find_if([](char c) { return c == ',' || c == '}'; });<br>
+<br>
+ if (CommaOrBracePos == StringRef::npos) {<br>
+ // Neither a comma nor the closing brace was found.<br>
+ if (Warn)<br>
+ H.HandleIncompleteSpecifier(Start, E - Start);<br>
+ return true;<br>
+ }<br>
+<br>
+ I += CommaOrBracePos + 1;<br>
+ }<br>
+ // Continue until the closing brace is found.<br>
+ } while (*(I - 1) == ',');<br>
+<br>
+ // Set the privacy flag.<br>
+ switch (PrivacyFlags) {<br>
+ case 0:<br>
+ break;<br>
+ case clang::analyze_os_log::OSLogBufferItem::IsPrivate:<br>
+ FS.setIsPrivate(MatchedStr.data());<br>
+ break;<br>
+ case clang::analyze_os_log::OSLogBufferItem::IsPublic:<br>
+ FS.setIsPublic(MatchedStr.data());<br>
+ break;<br>
+ default:<br>
+ llvm_unreachable("Unexpected privacy flag value");<br>
+ }<br>
+ }<br>
+<br>
+ // Look for flags (if any).<br>
+ bool hasMore = true;<br>
+ for ( ; I != E; ++I) {<br>
+ switch (*I) {<br>
+ default: hasMore = false; break;<br>
+ case '\'':<br>
+ // FIXME: POSIX specific. Always accept?<br>
+ FS.setHasThousandsGrouping(I);<br>
+ break;<br>
+ case '-': FS.setIsLeftJustified(I); break;<br>
+ case '+': FS.setHasPlusPrefix(I); break;<br>
+ case ' ': FS.setHasSpacePrefix(I); break;<br>
+ case '#': FS.setHasAlternativeForm(I); break;<br>
+ case '0': FS.setHasLeadingZeros(I); break;<br>
+ }<br>
+ if (!hasMore)<br>
+ break;<br>
+ }<br>
+<br>
+ if (I == E) {<br>
+ // No more characters left?<br>
+ if (Warn)<br>
+ H.HandleIncompleteSpecifier(Start, E - Start);<br>
+ return true;<br>
+ }<br>
+<br>
+ // Look for the field width (if any).<br>
+ if (ParseFieldWidth(H, FS, Start, I, E,<br>
+ FS.usesPositionalArg() ? nullptr : &argIndex))<br>
+ return true;<br>
+<br>
+ if (I == E) {<br>
+ // No more characters left?<br>
+ if (Warn)<br>
+ H.HandleIncompleteSpecifier(Start, E - Start);<br>
+ return true;<br>
+ }<br>
+<br>
+ // Look for the precision (if any).<br>
+ if (*I == '.') {<br>
+ ++I;<br>
+ if (I == E) {<br>
+ if (Warn)<br>
+ H.HandleIncompleteSpecifier(Start, E - Start);<br>
+ return true;<br>
+ }<br>
+<br>
+ if (ParsePrecision(H, FS, Start, I, E,<br>
+ FS.usesPositionalArg() ? nullptr : &argIndex))<br>
+ return true;<br>
+<br>
+ if (I == E) {<br>
+ // No more characters left?<br>
+ if (Warn)<br>
+ H.HandleIncompleteSpecifier(Start, E - Start);<br>
+ return true;<br>
+ }<br>
+ }<br>
+<br>
+ // Look for the length modifier.<br>
+ if (ParseLengthModifier(FS, I, E, LO) && I == E) {<br>
+ // No more characters left?<br>
+ if (Warn)<br>
+ H.HandleIncompleteSpecifier(Start, E - Start);<br>
+ return true;<br>
+ }<br>
+<br>
+ // Look for the Objective-C modifier flags, if any.<br>
+ // We parse these here, even if they don't apply to<br>
+ // the conversion specifier, and then emit an error<br>
+ // later if the conversion specifier isn't '@'. This<br>
+ // enables better recovery, and we don't know if<br>
+ // these flags are applicable until later.<br>
+ const char *ObjCModifierFlagsStart = nullptr,<br>
+ *ObjCModifierFlagsEnd = nullptr;<br>
+ if (*I == '[') {<br>
+ ObjCModifierFlagsStart = I;<br>
+ ++I;<br>
+ auto flagStart = I;<br>
+ for (;; ++I) {<br>
+ ObjCModifierFlagsEnd = I;<br>
+ if (I == E) {<br>
+ if (Warn)<br>
+ H.HandleIncompleteSpecifier(Start, E - Start);<br>
+ return true;<br>
+ }<br>
+ // Did we find the closing ']'?<br>
+ if (*I == ']') {<br>
+ if (ParseObjCFlags(H, FS, flagStart, I, Warn))<br>
+ return true;<br>
+ ++I;<br>
+ break;<br>
+ }<br>
+ // There are no separators defined yet for multiple<br>
+ // Objective-C modifier flags. When those are<br>
+ // defined, this is the place to check.<br>
+ }<br>
+ }<br>
+<br>
+ if (*I == '\0') {<br>
+ // Detect spurious null characters, which are likely errors.<br>
+ H.HandleNullChar(I);<br>
+ return true;<br>
+ }<br>
+<br>
+ // Finally, look for the conversion specifier.<br>
+ const char *conversionPosition = I++;<br>
+ ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;<br>
+ switch (*conversionPosition) {<br>
+ default:<br>
+ break;<br>
+ // C99: 7.19.6.1 (section 8).<br>
+ case '%': k = ConversionSpecifier::PercentArg; break;<br>
+ case 'A': k = ConversionSpecifier::AArg; break;<br>
+ case 'E': k = ConversionSpecifier::EArg; break;<br>
+ case 'F': k = ConversionSpecifier::FArg; break;<br>
+ case 'G': k = ConversionSpecifier::GArg; break;<br>
+ case 'X': k = ConversionSpecifier::XArg; break;<br>
+ case 'a': k = ConversionSpecifier::aArg; break;<br>
+ case 'c': k = ConversionSpecifier::cArg; break;<br>
+ case 'd': k = ConversionSpecifier::dArg; break;<br>
+ case 'e': k = ConversionSpecifier::eArg; break;<br>
+ case 'f': k = ConversionSpecifier::fArg; break;<br>
+ case 'g': k = ConversionSpecifier::gArg; break;<br>
+ case 'i': k = ConversionSpecifier::iArg; break;<br>
+ case 'n': k = ConversionSpecifier::nArg; break;<br>
+ case 'o': k = ConversionSpecifier::oArg; break;<br>
+ case 'p': k = ConversionSpecifier::pArg; break;<br>
+ case 's': k = ConversionSpecifier::sArg; break;<br>
+ case 'u': k = ConversionSpecifier::uArg; break;<br>
+ case 'x': k = ConversionSpecifier::xArg; break;<br>
+ // POSIX specific.<br>
+ case 'C': k = ConversionSpecifier::CArg; break;<br>
+ case 'S': k = ConversionSpecifier::SArg; break;<br>
+ // Apple extension for os_log<br>
+ case 'P':<br>
+ k = ConversionSpecifier::PArg;<br>
+ break;<br>
+ // Objective-C.<br>
+ case '@': k = ConversionSpecifier::ObjCObjArg; break;<br>
+ // Glibc specific.<br>
+ case 'm': k = ConversionSpecifier::PrintErrno; break;<br>
+ // FreeBSD kernel specific.<br>
+ case 'b':<br>
+ if (isFreeBSDKPrintf)<br>
+ k = ConversionSpecifier::FreeBSDbArg; // int followed by char *<br>
+ break;<br>
+ case 'r':<br>
+ if (isFreeBSDKPrintf)<br>
+ k = ConversionSpecifier::FreeBSDrArg; // int<br>
+ break;<br>
+ case 'y':<br>
+ if (isFreeBSDKPrintf)<br>
+ k = ConversionSpecifier::FreeBSDyArg; // int<br>
+ break;<br>
+ // Apple-specific.<br>
+ case 'D':<br>
+ if (isFreeBSDKPrintf)<br>
+ k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *<br>
+ else if (Target.getTriple().isOSDarwin())<br>
+ k = ConversionSpecifier::DArg;<br>
+ break;<br>
+ case 'O':<br>
+ if (Target.getTriple().isOSDarwin())<br>
+ k = ConversionSpecifier::OArg;<br>
+ break;<br>
+ case 'U':<br>
+ if (Target.getTriple().isOSDarwin())<br>
+ k = ConversionSpecifier::UArg;<br>
+ break;<br>
+ // MS specific.<br>
+ case 'Z':<br>
+ if (Target.getTriple().isOSMSVCRT())<br>
+ k = ConversionSpecifier::ZArg;<br>
+ }<br>
+<br>
+ // Check to see if we used the Objective-C modifier flags with<br>
+ // a conversion specifier other than '@'.<br>
+ if (k != ConversionSpecifier::ObjCObjArg &&<br>
+ k != ConversionSpecifier::InvalidSpecifier &&<br>
+ ObjCModifierFlagsStart) {<br>
+ H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart,<br>
+ ObjCModifierFlagsEnd + 1,<br>
+ conversionPosition);<br>
+ return true;<br>
+ }<br>
+<br>
+ PrintfConversionSpecifier CS(conversionPosition, k);<br>
+ FS.setConversionSpecifier(CS);<br>
+ if (CS.consumesDataArgument() && !FS.usesPositionalArg())<br>
+ FS.setArgIndex(argIndex++);<br>
+ // FreeBSD kernel specific.<br>
+ if (k == ConversionSpecifier::FreeBSDbArg ||<br>
+ k == ConversionSpecifier::FreeBSDDArg)<br>
+ argIndex++;<br>
+<br>
+ if (k == ConversionSpecifier::InvalidSpecifier) {<br>
+ unsigned Len = I - Start;<br>
+ if (ParseUTF8InvalidSpecifier(Start, E, Len)) {<br>
+ CS.setEndScanList(Start + Len);<br>
+ FS.setConversionSpecifier(CS);<br>
+ }<br>
+ // Assume the conversion takes one argument.<br>
+ return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len);<br>
+ }<br>
+ return PrintfSpecifierResult(Start, FS);<br>
+}<br>
+<br>
+bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,<br>
+ const char *I,<br>
+ const char *E,<br>
+ const LangOptions &LO,<br>
+ const TargetInfo &Target,<br>
+ bool isFreeBSDKPrintf) {<br>
+<br>
+ unsigned argIndex = 0;<br>
+<br>
+ // Keep looking for a format specifier until we have exhausted the string.<br>
+ while (I != E) {<br>
+ const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,<br>
+ LO, Target, true,<br>
+ isFreeBSDKPrintf);<br>
+ // Did a fail-stop error of any kind occur when parsing the specifier?<br>
+ // If so, don't do any more processing.<br>
+ if (FSR.shouldStop())<br>
+ return true;<br>
+ // Did we exhaust the string or encounter an error that<br>
+ // we can recover from?<br>
+ if (!FSR.hasValue())<br>
+ continue;<br>
+ // We have a format specifier. Pass it to the callback.<br>
+ if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),<br>
+ I - FSR.getStart()))<br>
+ return true;<br>
+ }<br>
+ assert(I == E && "Format string not exhausted");<br>
+ return false;<br>
+}<br>
+<br>
+bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,<br>
+ const char *E,<br>
+ const LangOptions &LO,<br>
+ const TargetInfo &Target) {<br>
+<br>
+ unsigned argIndex = 0;<br>
+<br>
+ // Keep looking for a %s format specifier until we have exhausted the string.<br>
+ FormatStringHandler H;<br>
+ while (I != E) {<br>
+ const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,<br>
+ LO, Target, false,<br>
+ false);<br>
+ // Did a fail-stop error of any kind occur when parsing the specifier?<br>
+ // If so, don't do any more processing.<br>
+ if (FSR.shouldStop())<br>
+ return false;<br>
+ // Did we exhaust the string or encounter an error that<br>
+ // we can recover from?<br>
+ if (!FSR.hasValue())<br>
+ continue;<br>
+ const analyze_printf::PrintfSpecifier &FS = FSR.getValue();<br>
+ // Return true if this a %s format specifier.<br>
+ if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg)<br>
+ return true;<br>
+ }<br>
+ return false;<br>
+}<br>
+<br>
+//===----------------------------------------------------------------------===//<br>
+// Methods on PrintfSpecifier.<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,<br>
+ bool IsObjCLiteral) const {<br>
+ const PrintfConversionSpecifier &CS = getConversionSpecifier();<br>
+<br>
+ if (!CS.consumesDataArgument())<br>
+ return ArgType::Invalid();<br>
+<br>
+ if (CS.getKind() == ConversionSpecifier::cArg)<br>
+ switch (LM.getKind()) {<br>
+ case LengthModifier::None:<br>
+ return Ctx.IntTy;<br>
+ case LengthModifier::AsLong:<br>
+ case LengthModifier::AsWide:<br>
+ return ArgType(ArgType::WIntTy, "wint_t");<br>
+ case LengthModifier::AsShort:<br>
+ if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())<br>
+ return Ctx.IntTy;<br>
+ LLVM_FALLTHROUGH;<br>
+ default:<br>
+ return ArgType::Invalid();<br>
+ }<br>
+<br>
+ if (CS.isIntArg())<br>
+ switch (LM.getKind()) {<br>
+ case LengthModifier::AsLongDouble:<br>
+ // GNU extension.<br>
+ return Ctx.LongLongTy;<br>
+ case LengthModifier::None:<br>
+ return Ctx.IntTy;<br>
+ case LengthModifier::AsInt32:<br>
+ return ArgType(Ctx.IntTy, "__int32");<br>
+ case LengthModifier::AsChar: return ArgType::AnyCharTy;<br>
+ case LengthModifier::AsShort: return Ctx.ShortTy;<br>
+ case LengthModifier::AsLong: return Ctx.LongTy;<br>
+ case LengthModifier::AsLongLong:<br>
+ case LengthModifier::AsQuad:<br>
+ return Ctx.LongLongTy;<br>
+ case LengthModifier::AsInt64:<br>
+ return ArgType(Ctx.LongLongTy, "__int64");<br>
+ case LengthModifier::AsIntMax:<br>
+ return ArgType(Ctx.getIntMaxType(), "intmax_t");<br>
+ case LengthModifier::AsSizeT:<br>
+ return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(), "ssize_t"));<br>
+ case LengthModifier::AsInt3264:<br>
+ return Ctx.getTargetInfo().getTriple().isArch64Bit()<br>
+ ? ArgType(Ctx.LongLongTy, "__int64")<br>
+ : ArgType(Ctx.IntTy, "__int32");<br>
+ case LengthModifier::AsPtrDiff:<br>
+ return ArgType::makePtrdiffT(<br>
+ ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));<br>
+ case LengthModifier::AsAllocate:<br>
+ case LengthModifier::AsMAllocate:<br>
+ case LengthModifier::AsWide:<br>
+ return ArgType::Invalid();<br>
+ }<br>
+<br>
+ if (CS.isUIntArg())<br>
+ switch (LM.getKind()) {<br>
+ case LengthModifier::AsLongDouble:<br>
+ // GNU extension.<br>
+ return Ctx.UnsignedLongLongTy;<br>
+ case LengthModifier::None:<br>
+ return Ctx.UnsignedIntTy;<br>
+ case LengthModifier::AsInt32:<br>
+ return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");<br>
+ case LengthModifier::AsChar: return Ctx.UnsignedCharTy;<br>
+ case LengthModifier::AsShort: return Ctx.UnsignedShortTy;<br>
+ case LengthModifier::AsLong: return Ctx.UnsignedLongTy;<br>
+ case LengthModifier::AsLongLong:<br>
+ case LengthModifier::AsQuad:<br>
+ return Ctx.UnsignedLongLongTy;<br>
+ case LengthModifier::AsInt64:<br>
+ return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");<br>
+ case LengthModifier::AsIntMax:<br>
+ return ArgType(Ctx.getUIntMaxType(), "uintmax_t");<br>
+ case LengthModifier::AsSizeT:<br>
+ return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"));<br>
+ case LengthModifier::AsInt3264:<br>
+ return Ctx.getTargetInfo().getTriple().isArch64Bit()<br>
+ ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")<br>
+ : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");<br>
+ case LengthModifier::AsPtrDiff:<br>
+ return ArgType::makePtrdiffT(<br>
+ ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));<br>
+ case LengthModifier::AsAllocate:<br>
+ case LengthModifier::AsMAllocate:<br>
+ case LengthModifier::AsWide:<br>
+ return ArgType::Invalid();<br>
+ }<br>
+<br>
+ if (CS.isDoubleArg()) {<br>
+ if (LM.getKind() == LengthModifier::AsLongDouble)<br>
+ return Ctx.LongDoubleTy;<br>
+ return Ctx.DoubleTy;<br>
+ }<br>
+<br>
+ if (CS.getKind() == ConversionSpecifier::nArg) {<br>
+ switch (LM.getKind()) {<br>
+ case LengthModifier::None:<br>
+ return ArgType::PtrTo(Ctx.IntTy);<br>
+ case LengthModifier::AsChar:<br>
+ return ArgType::PtrTo(Ctx.SignedCharTy);<br>
+ case LengthModifier::AsShort:<br>
+ return ArgType::PtrTo(Ctx.ShortTy);<br>
+ case LengthModifier::AsLong:<br>
+ return ArgType::PtrTo(Ctx.LongTy);<br>
+ case LengthModifier::AsLongLong:<br>
+ case LengthModifier::AsQuad:<br>
+ return ArgType::PtrTo(Ctx.LongLongTy);<br>
+ case LengthModifier::AsIntMax:<br>
+ return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));<br>
+ case LengthModifier::AsSizeT:<br>
+ return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));<br>
+ case LengthModifier::AsPtrDiff:<br>
+ return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));<br>
+ case LengthModifier::AsLongDouble:<br>
+ return ArgType(); // FIXME: Is this a known extension?<br>
+ case LengthModifier::AsAllocate:<br>
+ case LengthModifier::AsMAllocate:<br>
+ case LengthModifier::AsInt32:<br>
+ case LengthModifier::AsInt3264:<br>
+ case LengthModifier::AsInt64:<br>
+ case LengthModifier::AsWide:<br>
+ return ArgType::Invalid();<br>
+ }<br>
+ }<br>
+<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::sArg:<br>
+ if (LM.getKind() == LengthModifier::AsWideChar) {<br>
+ if (IsObjCLiteral)<br>
+ return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),<br>
+ "const unichar *");<br>
+ return ArgType(ArgType::WCStrTy, "wchar_t *");<br>
+ }<br>
+ if (LM.getKind() == LengthModifier::AsWide)<br>
+ return ArgType(ArgType::WCStrTy, "wchar_t *");<br>
+ return ArgType::CStrTy;<br>
+ case ConversionSpecifier::SArg:<br>
+ if (IsObjCLiteral)<br>
+ return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),<br>
+ "const unichar *");<br>
+ if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&<br>
+ LM.getKind() == LengthModifier::AsShort)<br>
+ return ArgType::CStrTy;<br>
+ return ArgType(ArgType::WCStrTy, "wchar_t *");<br>
+ case ConversionSpecifier::CArg:<br>
+ if (IsObjCLiteral)<br>
+ return ArgType(Ctx.UnsignedShortTy, "unichar");<br>
+ if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&<br>
+ LM.getKind() == LengthModifier::AsShort)<br>
+ return Ctx.IntTy;<br>
+ return ArgType(Ctx.WideCharTy, "wchar_t");<br>
+ case ConversionSpecifier::pArg:<br>
+ case ConversionSpecifier::PArg:<br>
+ return ArgType::CPointerTy;<br>
+ case ConversionSpecifier::ObjCObjArg:<br>
+ return ArgType::ObjCPointerTy;<br>
+ default:<br>
+ break;<br>
+ }<br>
+<br>
+ // FIXME: Handle other cases.<br>
+ return ArgType();<br>
+}<br>
+<br>
+bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,<br>
+ ASTContext &Ctx, bool IsObjCLiteral) {<br>
+ // %n is different from other conversion specifiers; don't try to fix it.<br>
+ if (CS.getKind() == ConversionSpecifier::nArg)<br>
+ return false;<br>
+<br>
+ // Handle Objective-C objects first. Note that while the '%@' specifier will<br>
+ // not warn for structure pointer or void pointer arguments (because that's<br>
+ // how CoreFoundation objects are implemented), we only show a fixit for '%@'<br>
+ // if we know it's an object (block, id, class, or __attribute__((NSObject))).<br>
+ if (QT->isObjCRetainableType()) {<br>
+ if (!IsObjCLiteral)<br>
+ return false;<br>
+<br>
+ CS.setKind(ConversionSpecifier::ObjCObjArg);<br>
+<br>
+ // Disable irrelevant flags<br>
+ HasThousandsGrouping = false;<br>
+ HasPlusPrefix = false;<br>
+ HasSpacePrefix = false;<br>
+ HasAlternativeForm = false;<br>
+ HasLeadingZeroes = false;<br>
+ Precision.setHowSpecified(OptionalAmount::NotSpecified);<br>
+ LM.setKind(LengthModifier::None);<br>
+<br>
+ return true;<br>
+ }<br>
+<br>
+ // Handle strings next (char *, wchar_t *)<br>
+ if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {<br>
+ CS.setKind(ConversionSpecifier::sArg);<br>
+<br>
+ // Disable irrelevant flags<br>
+ HasAlternativeForm = 0;<br>
+ HasLeadingZeroes = 0;<br>
+<br>
+ // Set the long length modifier for wide characters<br>
+ if (QT->getPointeeType()->isWideCharType())<br>
+ LM.setKind(LengthModifier::AsWideChar);<br>
+ else<br>
+ LM.setKind(LengthModifier::None);<br>
+<br>
+ return true;<br>
+ }<br>
+<br>
+ // If it's an enum, get its underlying type.<br>
+ if (const EnumType *ETy = QT->getAs<EnumType>())<br>
+ QT = ETy->getDecl()->getIntegerType();<br>
+<br>
+ // We can only work with builtin types.<br>
+ const BuiltinType *BT = QT->getAs<BuiltinType>();<br>
+ if (!BT)<br>
+ return false;<br>
+<br>
+ // Set length modifier<br>
+ switch (BT->getKind()) {<br>
+ case BuiltinType::Bool:<br>
+ case BuiltinType::WChar_U:<br>
+ case BuiltinType::WChar_S:<br>
+ case BuiltinType::Char8: // FIXME: Treat like 'char'?<br>
+ case BuiltinType::Char16:<br>
+ case BuiltinType::Char32:<br>
+ case BuiltinType::UInt128:<br>
+ case BuiltinType::Int128:<br>
+ case BuiltinType::Half:<br>
+ case BuiltinType::Float16:<br>
+ case BuiltinType::Float128:<br>
+ case BuiltinType::ShortAccum:<br>
+ case BuiltinType::Accum:<br>
+ case BuiltinType::LongAccum:<br>
+ case BuiltinType::UShortAccum:<br>
+ case BuiltinType::UAccum:<br>
+ case BuiltinType::ULongAccum:<br>
+ case BuiltinType::ShortFract:<br>
+ case BuiltinType::Fract:<br>
+ case BuiltinType::LongFract:<br>
+ case BuiltinType::UShortFract:<br>
+ case BuiltinType::UFract:<br>
+ case BuiltinType::ULongFract:<br>
+ case BuiltinType::SatShortAccum:<br>
+ case BuiltinType::SatAccum:<br>
+ case BuiltinType::SatLongAccum:<br>
+ case BuiltinType::SatUShortAccum:<br>
+ case BuiltinType::SatUAccum:<br>
+ case BuiltinType::SatULongAccum:<br>
+ case BuiltinType::SatShortFract:<br>
+ case BuiltinType::SatFract:<br>
+ case BuiltinType::SatLongFract:<br>
+ case BuiltinType::SatUShortFract:<br>
+ case BuiltinType::SatUFract:<br>
+ case BuiltinType::SatULongFract:<br>
+ // Various types which are non-trivial to correct.<br>
+ return false;<br>
+<br>
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \<br>
+ case BuiltinType::Id:<br>
+#include "clang/Basic/OpenCLImageTypes.def"<br>
+#define SIGNED_TYPE(Id, SingletonId)<br>
+#define UNSIGNED_TYPE(Id, SingletonId)<br>
+#define FLOATING_TYPE(Id, SingletonId)<br>
+#define BUILTIN_TYPE(Id, SingletonId) \<br>
+ case BuiltinType::Id:<br>
+#include "clang/AST/BuiltinTypes.def"<br>
+ // Misc other stuff which doesn't make sense here.<br>
+ return false;<br>
+<br>
+ case BuiltinType::UInt:<br>
+ case BuiltinType::Int:<br>
+ case BuiltinType::Float:<br>
+ case BuiltinType::Double:<br>
+ LM.setKind(LengthModifier::None);<br>
+ break;<br>
+<br>
+ case BuiltinType::Char_U:<br>
+ case BuiltinType::UChar:<br>
+ case BuiltinType::Char_S:<br>
+ case BuiltinType::SChar:<br>
+ LM.setKind(LengthModifier::AsChar);<br>
+ break;<br>
+<br>
+ case BuiltinType::Short:<br>
+ case BuiltinType::UShort:<br>
+ LM.setKind(LengthModifier::AsShort);<br>
+ break;<br>
+<br>
+ case BuiltinType::Long:<br>
+ case BuiltinType::ULong:<br>
+ LM.setKind(LengthModifier::AsLong);<br>
+ break;<br>
+<br>
+ case BuiltinType::LongLong:<br>
+ case BuiltinType::ULongLong:<br>
+ LM.setKind(LengthModifier::AsLongLong);<br>
+ break;<br>
+<br>
+ case BuiltinType::LongDouble:<br>
+ LM.setKind(LengthModifier::AsLongDouble);<br>
+ break;<br>
+ }<br>
+<br>
+ // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.<br>
+ if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))<br>
+ namedTypeToLengthModifier(QT, LM);<br>
+<br>
+ // If fixing the length modifier was enough, we might be done.<br>
+ if (hasValidLengthModifier(Ctx.getTargetInfo())) {<br>
+ // If we're going to offer a fix anyway, make sure the sign matches.<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::uArg:<br>
+ case ConversionSpecifier::UArg:<br>
+ if (QT->isSignedIntegerType())<br>
+ CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);<br>
+ break;<br>
+ case ConversionSpecifier::dArg:<br>
+ case ConversionSpecifier::DArg:<br>
+ case ConversionSpecifier::iArg:<br>
+ if (QT->isUnsignedIntegerType() && !HasPlusPrefix)<br>
+ CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);<br>
+ break;<br>
+ default:<br>
+ // Other specifiers do not have signed/unsigned variants.<br>
+ break;<br>
+ }<br>
+<br>
+ const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);<br>
+ if (ATR.isValid() && ATR.matchesType(Ctx, QT))<br>
+ return true;<br>
+ }<br>
+<br>
+ // Set conversion specifier and disable any flags which do not apply to it.<br>
+ // Let typedefs to char fall through to int, as %c is silly for uint8_t.<br>
+ if (!isa<TypedefType>(QT) && QT->isCharType()) {<br>
+ CS.setKind(ConversionSpecifier::cArg);<br>
+ LM.setKind(LengthModifier::None);<br>
+ Precision.setHowSpecified(OptionalAmount::NotSpecified);<br>
+ HasAlternativeForm = 0;<br>
+ HasLeadingZeroes = 0;<br>
+ HasPlusPrefix = 0;<br>
+ }<br>
+ // Test for Floating type first as LongDouble can pass isUnsignedIntegerType<br>
+ else if (QT->isRealFloatingType()) {<br>
+ CS.setKind(ConversionSpecifier::fArg);<br>
+ }<br>
+ else if (QT->isSignedIntegerType()) {<br>
+ CS.setKind(ConversionSpecifier::dArg);<br>
+ HasAlternativeForm = 0;<br>
+ }<br>
+ else if (QT->isUnsignedIntegerType()) {<br>
+ CS.setKind(ConversionSpecifier::uArg);<br>
+ HasAlternativeForm = 0;<br>
+ HasPlusPrefix = 0;<br>
+ } else {<br>
+ llvm_unreachable("Unexpected type");<br>
+ }<br>
+<br>
+ return true;<br>
+}<br>
+<br>
+void PrintfSpecifier::toString(raw_ostream &os) const {<br>
+ // Whilst some features have no defined order, we are using the order<br>
+ // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)<br>
+ os << "%";<br>
+<br>
+ // Positional args<br>
+ if (usesPositionalArg()) {<br>
+ os << getPositionalArgIndex() << "$";<br>
+ }<br>
+<br>
+ // Conversion flags<br>
+ if (IsLeftJustified) os << "-";<br>
+ if (HasPlusPrefix) os << "+";<br>
+ if (HasSpacePrefix) os << " ";<br>
+ if (HasAlternativeForm) os << "#";<br>
+ if (HasLeadingZeroes) os << "0";<br>
+<br>
+ // Minimum field width<br>
+ FieldWidth.toString(os);<br>
+ // Precision<br>
+ Precision.toString(os);<br>
+ // Length modifier<br>
+ os << LM.toString();<br>
+ // Conversion specifier<br>
+ os << CS.toString();<br>
+}<br>
+<br>
+bool PrintfSpecifier::hasValidPlusPrefix() const {<br>
+ if (!HasPlusPrefix)<br>
+ return true;<br>
+<br>
+ // The plus prefix only makes sense for signed conversions<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::dArg:<br>
+ case ConversionSpecifier::DArg:<br>
+ case ConversionSpecifier::iArg:<br>
+ case ConversionSpecifier::fArg:<br>
+ case ConversionSpecifier::FArg:<br>
+ case ConversionSpecifier::eArg:<br>
+ case ConversionSpecifier::EArg:<br>
+ case ConversionSpecifier::gArg:<br>
+ case ConversionSpecifier::GArg:<br>
+ case ConversionSpecifier::aArg:<br>
+ case ConversionSpecifier::AArg:<br>
+ case ConversionSpecifier::FreeBSDrArg:<br>
+ case ConversionSpecifier::FreeBSDyArg:<br>
+ return true;<br>
+<br>
+ default:<br>
+ return false;<br>
+ }<br>
+}<br>
+<br>
+bool PrintfSpecifier::hasValidAlternativeForm() const {<br>
+ if (!HasAlternativeForm)<br>
+ return true;<br>
+<br>
+ // Alternate form flag only valid with the oxXaAeEfFgG conversions<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::oArg:<br>
+ case ConversionSpecifier::OArg:<br>
+ case ConversionSpecifier::xArg:<br>
+ case ConversionSpecifier::XArg:<br>
+ case ConversionSpecifier::aArg:<br>
+ case ConversionSpecifier::AArg:<br>
+ case ConversionSpecifier::eArg:<br>
+ case ConversionSpecifier::EArg:<br>
+ case ConversionSpecifier::fArg:<br>
+ case ConversionSpecifier::FArg:<br>
+ case ConversionSpecifier::gArg:<br>
+ case ConversionSpecifier::GArg:<br>
+ case ConversionSpecifier::FreeBSDrArg:<br>
+ case ConversionSpecifier::FreeBSDyArg:<br>
+ return true;<br>
+<br>
+ default:<br>
+ return false;<br>
+ }<br>
+}<br>
+<br>
+bool PrintfSpecifier::hasValidLeadingZeros() const {<br>
+ if (!HasLeadingZeroes)<br>
+ return true;<br>
+<br>
+ // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::dArg:<br>
+ case ConversionSpecifier::DArg:<br>
+ case ConversionSpecifier::iArg:<br>
+ case ConversionSpecifier::oArg:<br>
+ case ConversionSpecifier::OArg:<br>
+ case ConversionSpecifier::uArg:<br>
+ case ConversionSpecifier::UArg:<br>
+ case ConversionSpecifier::xArg:<br>
+ case ConversionSpecifier::XArg:<br>
+ case ConversionSpecifier::aArg:<br>
+ case ConversionSpecifier::AArg:<br>
+ case ConversionSpecifier::eArg:<br>
+ case ConversionSpecifier::EArg:<br>
+ case ConversionSpecifier::fArg:<br>
+ case ConversionSpecifier::FArg:<br>
+ case ConversionSpecifier::gArg:<br>
+ case ConversionSpecifier::GArg:<br>
+ case ConversionSpecifier::FreeBSDrArg:<br>
+ case ConversionSpecifier::FreeBSDyArg:<br>
+ return true;<br>
+<br>
+ default:<br>
+ return false;<br>
+ }<br>
+}<br>
+<br>
+bool PrintfSpecifier::hasValidSpacePrefix() const {<br>
+ if (!HasSpacePrefix)<br>
+ return true;<br>
+<br>
+ // The space prefix only makes sense for signed conversions<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::dArg:<br>
+ case ConversionSpecifier::DArg:<br>
+ case ConversionSpecifier::iArg:<br>
+ case ConversionSpecifier::fArg:<br>
+ case ConversionSpecifier::FArg:<br>
+ case ConversionSpecifier::eArg:<br>
+ case ConversionSpecifier::EArg:<br>
+ case ConversionSpecifier::gArg:<br>
+ case ConversionSpecifier::GArg:<br>
+ case ConversionSpecifier::aArg:<br>
+ case ConversionSpecifier::AArg:<br>
+ case ConversionSpecifier::FreeBSDrArg:<br>
+ case ConversionSpecifier::FreeBSDyArg:<br>
+ return true;<br>
+<br>
+ default:<br>
+ return false;<br>
+ }<br>
+}<br>
+<br>
+bool PrintfSpecifier::hasValidLeftJustified() const {<br>
+ if (!IsLeftJustified)<br>
+ return true;<br>
+<br>
+ // The left justified flag is valid for all conversions except n<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::nArg:<br>
+ return false;<br>
+<br>
+ default:<br>
+ return true;<br>
+ }<br>
+}<br>
+<br>
+bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {<br>
+ if (!HasThousandsGrouping)<br>
+ return true;<br>
+<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::dArg:<br>
+ case ConversionSpecifier::DArg:<br>
+ case ConversionSpecifier::iArg:<br>
+ case ConversionSpecifier::uArg:<br>
+ case ConversionSpecifier::UArg:<br>
+ case ConversionSpecifier::fArg:<br>
+ case ConversionSpecifier::FArg:<br>
+ case ConversionSpecifier::gArg:<br>
+ case ConversionSpecifier::GArg:<br>
+ return true;<br>
+ default:<br>
+ return false;<br>
+ }<br>
+}<br>
+<br>
+bool PrintfSpecifier::hasValidPrecision() const {<br>
+ if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)<br>
+ return true;<br>
+<br>
+ // Precision is only valid with the diouxXaAeEfFgGsP conversions<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::dArg:<br>
+ case ConversionSpecifier::DArg:<br>
+ case ConversionSpecifier::iArg:<br>
+ case ConversionSpecifier::oArg:<br>
+ case ConversionSpecifier::OArg:<br>
+ case ConversionSpecifier::uArg:<br>
+ case ConversionSpecifier::UArg:<br>
+ case ConversionSpecifier::xArg:<br>
+ case ConversionSpecifier::XArg:<br>
+ case ConversionSpecifier::aArg:<br>
+ case ConversionSpecifier::AArg:<br>
+ case ConversionSpecifier::eArg:<br>
+ case ConversionSpecifier::EArg:<br>
+ case ConversionSpecifier::fArg:<br>
+ case ConversionSpecifier::FArg:<br>
+ case ConversionSpecifier::gArg:<br>
+ case ConversionSpecifier::GArg:<br>
+ case ConversionSpecifier::sArg:<br>
+ case ConversionSpecifier::FreeBSDrArg:<br>
+ case ConversionSpecifier::FreeBSDyArg:<br>
+ case ConversionSpecifier::PArg:<br>
+ return true;<br>
+<br>
+ default:<br>
+ return false;<br>
+ }<br>
+}<br>
+bool PrintfSpecifier::hasValidFieldWidth() const {<br>
+ if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)<br>
+ return true;<br>
+<br>
+ // The field width is valid for all conversions except n<br>
+ switch (CS.getKind()) {<br>
+ case ConversionSpecifier::nArg:<br>
+ return false;<br>
+<br>
+ default:<br>
+ return true;<br>
+ }<br>
+}<br>
<br>
Added: cfe/trunk/lib/AST/ScanfFormatString.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ScanfFormatString.cpp?rev=345971&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ScanfFormatString.cpp?rev=345971&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/ScanfFormatString.cpp (added)<br>
+++ cfe/trunk/lib/AST/ScanfFormatString.cpp Fri Nov 2 06:14:11 2018<br>
@@ -0,0 +1,563 @@<br>
+//= ScanfFormatString.cpp - Analysis of printf format strings --*- C++ -*-===//<br>
+//<br>
+// The LLVM Compiler Infrastructure<br>
+//<br>
+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+//<br>
+// Handling of format string in scanf and friends. The structure of format<br>
+// strings for fscanf() are described in C99 7.19.6.2.<br>
+//<br>
+//===----------------------------------------------------------------------===//<br>
+<br>
+#include "clang/AST/FormatString.h"<br>
+#include "FormatStringParsing.h"<br>
+#include "clang/Basic/TargetInfo.h"<br>
+<br>
+using clang::analyze_format_string::ArgType;<br>
+using clang::analyze_format_string::FormatStringHandler;<br>
+using clang::analyze_format_string::LengthModifier;<br>
+using clang::analyze_format_string::OptionalAmount;<br>
+using clang::analyze_format_string::ConversionSpecifier;<br>
+using clang::analyze_scanf::ScanfConversionSpecifier;<br>
+using clang::analyze_scanf::ScanfSpecifier;<br>
+using clang::UpdateOnReturn;<br>
+using namespace clang;<br>
+<br>
+typedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier><br>
+ ScanfSpecifierResult;<br>
+<br>
+static bool ParseScanList(FormatStringHandler &H,<br>
+ ScanfConversionSpecifier &CS,<br>
+ const char *&Beg, const char *E) {<br>
+ const char *I = Beg;<br>
+ const char *start = I - 1;<br>
+ UpdateOnReturn <const char*> UpdateBeg(Beg, I);<br>
+<br>
+ // No more characters?<br>
+ if (I == E) {<br>
+ H.HandleIncompleteScanList(start, I);<br>
+ return true;<br>
+ }<br>
+<br>
+ // Special case: ']' is the first character.<br>
+ if (*I == ']') {<br>
+ if (++I == E) {<br>
+ H.HandleIncompleteScanList(start, I - 1);<br>
+ return true;<br>
+ }<br>
+ }<br>
+<br>
+ // Special case: "^]" are the first characters.<br>
+ if (I + 1 != E && I[0] == '^' && I[1] == ']') {<br>
+ I += 2;<br>
+ if (I == E) {<br>
+ H.HandleIncompleteScanList(start, I - 1);<br>
+ return true;<br>
+ }<br>
+ }<br>
+<br>
+ // Look for a ']' character which denotes the end of the scan list.<br>
+ while (*I != ']') {<br>
+ if (++I == E) {<br>
+ H.HandleIncompleteScanList(start, I - 1);<br>
+ return true;<br>
+ }<br>
+ }<br>
+<br>
+ CS.setEndScanList(I);<br>
+ return false;<br>
+}<br>
+<br>
+// FIXME: Much of this is copy-paste from ParsePrintfSpecifier.<br>
+// We can possibly refactor.<br>
+static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,<br>
+ const char *&Beg,<br>
+ const char *E,<br>
+ unsigned &argIndex,<br>
+ const LangOptions &LO,<br>
+ const TargetInfo &Target) {<br>
+ using namespace clang::analyze_format_string;<br>
+ using namespace clang::analyze_scanf;<br>
+ const char *I = Beg;<br>
+ const char *Start = nullptr;<br>
+ UpdateOnReturn <const char*> UpdateBeg(Beg, I);<br>
+<br>
+ // Look for a '%' character that indicates the start of a format specifier.<br>
+ for ( ; I != E ; ++I) {<br>
+ char c = *I;<br>
+ if (c == '\0') {<br>
+ // Detect spurious null characters, which are likely errors.<br>
+ H.HandleNullChar(I);<br>
+ return true;<br>
+ }<br>
+ if (c == '%') {<br>
+ Start = I++; // Record the start of the format specifier.<br>
+ break;<br>
+ }<br>
+ }<br>
+<br>
+ // No format specifier found?<br>
+ if (!Start)<br>
+ return false;<br>
+<br>
+ if (I == E) {<br>
+ // No more characters left?<br>
+ H.HandleIncompleteSpecifier(Start, E - Start);<br>
+ return true;<br>
+ }<br>
+<br>
+ ScanfSpecifier FS;<br>
+ if (ParseArgPosition(H, FS, Start, I, E))<br>
+ return true;<br>
+<br>
+ if (I == E) {<br>
+ // No more characters left?<br>
+ H.HandleIncompleteSpecifier(Start, E - Start);<br>
+ return true;<br>
+ }<br>
+<br>
+ // Look for '*' flag if it is present.<br>
+ if (*I == '*') {<br>
+ FS.setSuppressAssignment(I);<br>
+ if (++I == E) {<br>
+ H.HandleIncompleteSpecifier(Start, E - Start);<br>
+ return true;<br>
+ }<br>
+ }<br>
+<br>
+ // Look for the field width (if any). Unlike printf, this is either<br>
+ // a fixed integer or isn't present.<br>
+ const OptionalAmount &Amt = clang::analyze_format_string::ParseAmount(I, E);<br>
+ if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) {<br>
+ assert(Amt.getHowSpecified() == OptionalAmount::Constant);<br>
+ FS.setFieldWidth(Amt);<br>
+<br>
+ if (I == E) {<br>
+ // No more characters left?<br>
+ H.HandleIncompleteSpecifier(Start, E - Start);<br>
+ return true;<br>
+ }<br>
+ }<br>
+<br>
+ // Look for the length modifier.<br>
+ if (ParseLengthModifier(FS, I, E, LO, /*scanf=*/true) && I == E) {<br>
+ // No more characters left?<br>
+ H.HandleIncompleteSpecifier(Start, E - Start);<br>
+ return true;<br>
+ }<br>
+<br>
+ // Detect spurious null characters, which are likely errors.<br>
+ if (*I == '\0') {<br>
+ H.HandleNullChar(I);<br>
+ return true;<br>
+ }<br>
+<br>
+ // Finally, look for the conversion specifier.<br>
+ const char *conversionPosition = I++;<br>
+ ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier;<br>
+ switch (*conversionPosition) {<br>
+ default:<br>
+ break;<br>
+ case '%': k = ConversionSpecifier::PercentArg; break;<br>
+ case 'A': k = ConversionSpecifier::AArg; break;<br>
+ case 'E': k = ConversionSpecifier::EArg; break;<br>
+ case 'F': k = ConversionSpecifier::FArg; break;<br>
+ case 'G': k = ConversionSpecifier::GArg; break;<br>
+ case 'X': k = ConversionSpecifier::XArg; break;<br>
+ case 'a': k = ConversionSpecifier::aArg; break;<br>
+ case 'd': k = ConversionSpecifier::dArg; break;<br>
+ case 'e': k = ConversionSpecifier::eArg; break;<br>
+ case 'f': k = ConversionSpecifier::fArg; break;<br>
+ case 'g': k = ConversionSpecifier::gArg; break;<br>
+ case 'i': k = ConversionSpecifier::iArg; break;<br>
+ case 'n': k = ConversionSpecifier::nArg; break;<br>
+ case 'c': k = ConversionSpecifier::cArg; break;<br>
+ case 'C': k = ConversionSpecifier::CArg; break;<br>
+ case 'S': k = ConversionSpecifier::SArg; break;<br>
+ case '[': k = ConversionSpecifier::ScanListArg; break;<br>
+ case 'u': k = ConversionSpecifier::uArg; break;<br>
+ case 'x': k = ConversionSpecifier::xArg; break;<br>
+ case 'o': k = ConversionSpecifier::oArg; break;<br>
+ case 's': k = ConversionSpecifier::sArg; break;<br>
+ case 'p': k = ConversionSpecifier::pArg; break;<br>
+ // Apple extensions<br>
+ // Apple-specific<br>
+ case 'D':<br>
+ if (Target.getTriple().isOSDarwin())<br>
+ k = ConversionSpecifier::DArg;<br>
+ break;<br>
+ case 'O':<br>
+ if (Target.getTriple().isOSDarwin())<br>
+ k = ConversionSpecifier::OArg;<br>
+ break;<br>
+ case 'U':<br>
+ if (Target.getTriple().isOSDarwin())<br>
+ k = ConversionSpecifier::UArg;<br>
+ break;<br>
+ }<br>
+ ScanfConversionSpecifier CS(conversionPosition, k);<br>
+ if (k == ScanfConversionSpecifier::ScanListArg) {<br>
+ if (ParseScanList(H, CS, I, E))<br>
+ return true;<br>
+ }<br>
+ FS.setConversionSpecifier(CS);<br>
+ if (CS.consumesDataArgument() && !FS.getSuppressAssignment()<br>
+ && !FS.usesPositionalArg())<br>
+ FS.setArgIndex(argIndex++);<br>
+<br>
+ // FIXME: '%' and '*' doesn't make sense. Issue a warning.<br>
+ // FIXME: 'ConsumedSoFar' and '*' doesn't make sense.<br>
+<br>
+ if (k == ScanfConversionSpecifier::InvalidSpecifier) {<br>
+ unsigned Len = I - Beg;<br>
+ if (ParseUTF8InvalidSpecifier(Beg, E, Len)) {<br>
+ CS.setEndScanList(Beg + Len);<br>
+ FS.setConversionSpecifier(CS);<br>
+ }<br>
+ // Assume the conversion takes one argument.<br>
+ return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len);<br>
+ }<br>
+ return ScanfSpecifierResult(Start, FS);<br>
+}<br>
+<br>
+ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {<br>
+ const ScanfConversionSpecifier &CS = getConversionSpecifier();<br>
+<br>
+ if (!CS.consumesDataArgument())<br>
+ return ArgType::Invalid();<br>
+<br>
+ switch(CS.getKind()) {<br>
+ // Signed int.<br>
+ case ConversionSpecifier::dArg:<br>
+ case ConversionSpecifier::DArg:<br>
+ case ConversionSpecifier::iArg:<br>
+ switch (LM.getKind()) {<br>
+ case LengthModifier::None:<br>
+ return ArgType::PtrTo(Ctx.IntTy);<br>
+ case LengthModifier::AsChar:<br>
+ return ArgType::PtrTo(ArgType::AnyCharTy);<br>
+ case LengthModifier::AsShort:<br>
+ return ArgType::PtrTo(Ctx.ShortTy);<br>
+ case LengthModifier::AsLong:<br>
+ return ArgType::PtrTo(Ctx.LongTy);<br>
+ case LengthModifier::AsLongLong:<br>
+ case LengthModifier::AsQuad:<br>
+ return ArgType::PtrTo(Ctx.LongLongTy);<br>
+ case LengthModifier::AsInt64:<br>
+ return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));<br>
+ case LengthModifier::AsIntMax:<br>
+ return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));<br>
+ case LengthModifier::AsSizeT:<br>
+ return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));<br>
+ case LengthModifier::AsPtrDiff:<br>
+ return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));<br>
+ case LengthModifier::AsLongDouble:<br>
+ // GNU extension.<br>
+ return ArgType::PtrTo(Ctx.LongLongTy);<br>
+ case LengthModifier::AsAllocate:<br>
+ case LengthModifier::AsMAllocate:<br>
+ case LengthModifier::AsInt32:<br>
+ case LengthModifier::AsInt3264:<br>
+ case LengthModifier::AsWide:<br>
+ return ArgType::Invalid();<br>
+ }<br>
+<br>
+ // Unsigned int.<br>
+ case ConversionSpecifier::oArg:<br>
+ case ConversionSpecifier::OArg:<br>
+ case ConversionSpecifier::uArg:<br>
+ case ConversionSpecifier::UArg:<br>
+ case ConversionSpecifier::xArg:<br>
+ case ConversionSpecifier::XArg:<br>
+ switch (LM.getKind()) {<br>
+ case LengthModifier::None:<br>
+ return ArgType::PtrTo(Ctx.UnsignedIntTy);<br>
+ case LengthModifier::AsChar:<br>
+ return ArgType::PtrTo(Ctx.UnsignedCharTy);<br>
+ case LengthModifier::AsShort:<br>
+ return ArgType::PtrTo(Ctx.UnsignedShortTy);<br>
+ case LengthModifier::AsLong:<br>
+ return ArgType::PtrTo(Ctx.UnsignedLongTy);<br>
+ case LengthModifier::AsLongLong:<br>
+ case LengthModifier::AsQuad:<br>
+ return ArgType::PtrTo(Ctx.UnsignedLongLongTy);<br>
+ case LengthModifier::AsInt64:<br>
+ return ArgType::PtrTo(ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"));<br>
+ case LengthModifier::AsIntMax:<br>
+ return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t"));<br>
+ case LengthModifier::AsSizeT:<br>
+ return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));<br>
+ case LengthModifier::AsPtrDiff:<br>
+ return ArgType::PtrTo(<br>
+ ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));<br>
+ case LengthModifier::AsLongDouble:<br>
+ // GNU extension.<br>
+ return ArgType::PtrTo(Ctx.UnsignedLongLongTy);<br>
+ case LengthModifier::AsAllocate:<br>
+ case LengthModifier::AsMAllocate:<br>
+ case LengthModifier::AsInt32:<br>
+ case LengthModifier::AsInt3264:<br>
+ case LengthModifier::AsWide:<br>
+ return ArgType::Invalid();<br>
+ }<br>
+<br>
+ // Float.<br>
+ case ConversionSpecifier::aArg:<br>
+ case ConversionSpecifier::AArg:<br>
+ case ConversionSpecifier::eArg:<br>
+ case ConversionSpecifier::EArg:<br>
+ case ConversionSpecifier::fArg:<br>
+ case ConversionSpecifier::FArg:<br>
+ case ConversionSpecifier::gArg:<br>
+ case ConversionSpecifier::GArg:<br>
+ switch (LM.getKind()) {<br>
+ case LengthModifier::None:<br>
+ return ArgType::PtrTo(Ctx.FloatTy);<br>
+ case LengthModifier::AsLong:<br>
+ return ArgType::PtrTo(Ctx.DoubleTy);<br>
+ case LengthModifier::AsLongDouble:<br>
+ return ArgType::PtrTo(Ctx.LongDoubleTy);<br>
+ default:<br>
+ return ArgType::Invalid();<br>
+ }<br>
+<br>
+ // Char, string and scanlist.<br>
+ case ConversionSpecifier::cArg:<br>
+ case ConversionSpecifier::sArg:<br>
+ case ConversionSpecifier::ScanListArg:<br>
+ switch (LM.getKind()) {<br>
+ case LengthModifier::None:<br>
+ return ArgType::PtrTo(ArgType::AnyCharTy);<br>
+ case LengthModifier::AsLong:<br>
+ case LengthModifier::AsWide:<br>
+ return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));<br>
+ case LengthModifier::AsAllocate:<br>
+ case LengthModifier::AsMAllocate:<br>
+ return ArgType::PtrTo(ArgType::CStrTy);<br>
+ case LengthModifier::AsShort:<br>
+ if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())<br>
+ return ArgType::PtrTo(ArgType::AnyCharTy);<br>
+ LLVM_FALLTHROUGH;<br>
+ default:<br>
+ return ArgType::Invalid();<br>
+ }<br>
+ case ConversionSpecifier::CArg:<br>
+ case ConversionSpecifier::SArg:<br>
+ // FIXME: Mac OS X specific?<br>
+ switch (LM.getKind()) {<br>
+ case LengthModifier::None:<br>
+ case LengthModifier::AsWide:<br>
+ return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));<br>
+ case LengthModifier::AsAllocate:<br>
+ case LengthModifier::AsMAllocate:<br>
+ return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));<br>
+ case LengthModifier::AsShort:<br>
+ if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())<br>
+ return ArgType::PtrTo(ArgType::AnyCharTy);<br>
+ LLVM_FALLTHROUGH;<br>
+ default:<br>
+ return ArgType::Invalid();<br>
+ }<br>
+<br>
+ // Pointer.<br>
+ case ConversionSpecifier::pArg:<br>
+ return ArgType::PtrTo(ArgType::CPointerTy);<br>
+<br>
+ // Write-back.<br>
+ case ConversionSpecifier::nArg:<br>
+ switch (LM.getKind()) {<br>
+ case LengthModifier::None:<br>
+ return ArgType::PtrTo(Ctx.IntTy);<br>
+ case LengthModifier::AsChar:<br>
+ return ArgType::PtrTo(Ctx.SignedCharTy);<br>
+ case LengthModifier::AsShort:<br>
+ return ArgType::PtrTo(Ctx.ShortTy);<br>
+ case LengthModifier::AsLong:<br>
+ return ArgType::PtrTo(Ctx.LongTy);<br>
+ case LengthModifier::AsLongLong:<br>
+ case LengthModifier::AsQuad:<br>
+ return ArgType::PtrTo(Ctx.LongLongTy);<br>
+ case LengthModifier::AsInt64:<br>
+ return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));<br>
+ case LengthModifier::AsIntMax:<br>
+ return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));<br>
+ case LengthModifier::AsSizeT:<br>
+ return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));<br>
+ case LengthModifier::AsPtrDiff:<br>
+ return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));<br>
+ case LengthModifier::AsLongDouble:<br>
+ return ArgType(); // FIXME: Is this a known extension?<br>
+ case LengthModifier::AsAllocate:<br>
+ case LengthModifier::AsMAllocate:<br>
+ case LengthModifier::AsInt32:<br>
+ case LengthModifier::AsInt3264:<br>
+ case LengthModifier::AsWide:<br>
+ return ArgType::Invalid();<br>
+ }<br>
+<br>
+ default:<br>
+ break;<br>
+ }<br>
+<br>
+ return ArgType();<br>
+}<br>
+<br>
+bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,<br>
+ const LangOptions &LangOpt,<br>
+ ASTContext &Ctx) {<br>
+<br>
+ // %n is different from other conversion specifiers; don't try to fix it.<br>
+ if (CS.getKind() == ConversionSpecifier::nArg)<br>
+ return false;<br>
+<br>
+ if (!QT->isPointerType())<br>
+ return false;<br>
+<br>
+ QualType PT = QT->getPointeeType();<br>
+<br>
+ // If it's an enum, get its underlying type.<br>
+ if (const EnumType *ETy = PT->getAs<EnumType>()) {<br>
+ // Don't try to fix incomplete enums.<br>
+ if (!ETy->getDecl()->isComplete())<br>
+ return false;<br>
+ PT = ETy->getDecl()->getIntegerType();<br>
+ }<br>
+<br>
+ const BuiltinType *BT = PT->getAs<BuiltinType>();<br>
+ if (!BT)<br>
+ return false;<br>
+<br>
+ // Pointer to a character.<br>
+ if (PT->isAnyCharacterType()) {<br>
+ CS.setKind(ConversionSpecifier::sArg);<br>
+ if (PT->isWideCharType())<br>
+ LM.setKind(LengthModifier::AsWideChar);<br>
+ else<br>
+ LM.setKind(LengthModifier::None);<br>
+<br>
+ // If we know the target array length, we can use it as a field width.<br>
+ if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT)) {<br>
+ if (CAT->getSizeModifier() == ArrayType::Normal)<br>
+ FieldWidth = OptionalAmount(OptionalAmount::Constant,<br>
+ CAT->getSize().getZExtValue() - 1,<br>
+ "", 0, false);<br>
+<br>
+ }<br>
+ return true;<br>
+ }<br>
+<br>
+ // Figure out the length modifier.<br>
+ switch (BT->getKind()) {<br>
+ // no modifier<br>
+ case BuiltinType::UInt:<br>
+ case BuiltinType::Int:<br>
+ case BuiltinType::Float:<br>
+ LM.setKind(LengthModifier::None);<br>
+ break;<br>
+<br>
+ // hh<br>
+ case BuiltinType::Char_U:<br>
+ case BuiltinType::UChar:<br>
+ case BuiltinType::Char_S:<br>
+ case BuiltinType::SChar:<br>
+ LM.setKind(LengthModifier::AsChar);<br>
+ break;<br>
+<br>
+ // h<br>
+ case BuiltinType::Short:<br>
+ case BuiltinType::UShort:<br>
+ LM.setKind(LengthModifier::AsShort);<br>
+ break;<br>
+<br>
+ // l<br>
+ case BuiltinType::Long:<br>
+ case BuiltinType::ULong:<br>
+ case BuiltinType::Double:<br>
+ LM.setKind(LengthModifier::AsLong);<br>
+ break;<br>
+<br>
+ // ll<br>
+ case BuiltinType::LongLong:<br>
+ case BuiltinType::ULongLong:<br>
+ LM.setKind(LengthModifier::AsLongLong);<br>
+ break;<br>
+<br>
+ // L<br>
+ case BuiltinType::LongDouble:<br>
+ LM.setKind(LengthModifier::AsLongDouble);<br>
+ break;<br>
+<br>
+ // Don't know.<br>
+ default:<br>
+ return false;<br>
+ }<br>
+<br>
+ // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.<br>
+ if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus11))<br>
+ namedTypeToLengthModifier(PT, LM);<br>
+<br>
+ // If fixing the length modifier was enough, we are done.<br>
+ if (hasValidLengthModifier(Ctx.getTargetInfo())) {<br>
+ const analyze_scanf::ArgType &AT = getArgType(Ctx);<br>
+ if (AT.isValid() && AT.matchesType(Ctx, QT))<br>
+ return true;<br>
+ }<br>
+<br>
+ // Figure out the conversion specifier.<br>
+ if (PT->isRealFloatingType())<br>
+ CS.setKind(ConversionSpecifier::fArg);<br>
+ else if (PT->isSignedIntegerType())<br>
+ CS.setKind(ConversionSpecifier::dArg);<br>
+ else if (PT->isUnsignedIntegerType())<br>
+ CS.setKind(ConversionSpecifier::uArg);<br>
+ else<br>
+ llvm_unreachable("Unexpected type");<br>
+<br>
+ return true;<br>
+}<br>
+<br>
+void ScanfSpecifier::toString(raw_ostream &os) const {<br>
+ os << "%";<br>
+<br>
+ if (usesPositionalArg())<br>
+ os << getPositionalArgIndex() << "$";<br>
+ if (SuppressAssignment)<br>
+ os << "*";<br>
+<br>
+ FieldWidth.toString(os);<br>
+ os << LM.toString();<br>
+ os << CS.toString();<br>
+}<br>
+<br>
+bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,<br>
+ const char *I,<br>
+ const char *E,<br>
+ const LangOptions &LO,<br>
+ const TargetInfo &Target) {<br>
+<br>
+ unsigned argIndex = 0;<br>
+<br>
+ // Keep looking for a format specifier until we have exhausted the string.<br>
+ while (I != E) {<br>
+ const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex,<br>
+ LO, Target);<br>
+ // Did a fail-stop error of any kind occur when parsing the specifier?<br>
+ // If so, don't do any more processing.<br>
+ if (FSR.shouldStop())<br>
+ return true;<br>
+ // Did we exhaust the string or encounter an error that<br>
+ // we can recover from?<br>
+ if (!FSR.hasValue())<br>
+ continue;<br>
+ // We have a format specifier. Pass it to the callback.<br>
+ if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(),<br>
+ I - FSR.getStart())) {<br>
+ return true;<br>
+ }<br>
+ }<br>
+ assert(I == E && "Format string not exhausted");<br>
+ return false;<br>
+}<br>
<br>
Modified: cfe/trunk/lib/Analysis/CMakeLists.txt<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CMakeLists.txt?rev=345971&r1=345970&r2=345971&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CMakeLists.txt?rev=345971&r1=345970&r2=345971&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Analysis/CMakeLists.txt (original)<br>
+++ cfe/trunk/lib/Analysis/CMakeLists.txt Fri Nov 2 06:14:11 2018<br>
@@ -16,15 +16,11 @@ add_clang_library(clangAnalysis<br>
CodeInjector.cpp<br>
Dominators.cpp<br>
ExprMutationAnalyzer.cpp<br>
- FormatString.cpp<br>
LiveVariables.cpp<br>
- OSLog.cpp<br>
ObjCNoReturn.cpp<br>
PostOrderCFGView.cpp<br>
- PrintfFormatString.cpp<br>
ProgramPoint.cpp<br>
ReachableCode.cpp<br>
- ScanfFormatString.cpp<br>
ThreadSafety.cpp<br>
ThreadSafetyCommon.cpp<br>
ThreadSafetyLogical.cpp<br>
<br>
Removed: cfe/trunk/lib/Analysis/FormatString.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/FormatString.cpp?rev=345970&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/FormatString.cpp?rev=345970&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Analysis/FormatString.cpp (original)<br>
+++ cfe/trunk/lib/Analysis/FormatString.cpp (removed)<br>
@@ -1,955 +0,0 @@<br>
-// FormatString.cpp - Common stuff for handling printf/scanf formats -*- C++ -*-<br>
-//<br>
-// The LLVM Compiler Infrastructure<br>
-//<br>
-// This file is distributed under the University of Illinois Open Source<br>
-// License. See LICENSE.TXT for details.<br>
-//<br>
-//===----------------------------------------------------------------------===//<br>
-//<br>
-// Shared details for processing format strings of printf and scanf<br>
-// (and friends).<br>
-//<br>
-//===----------------------------------------------------------------------===//<br>
-<br>
-#include "FormatStringParsing.h"<br>
-#include "clang/Basic/LangOptions.h"<br>
-#include "clang/Basic/TargetInfo.h"<br>
-#include "llvm/Support/ConvertUTF.h"<br>
-<br>
-using clang::analyze_format_string::ArgType;<br>
-using clang::analyze_format_string::FormatStringHandler;<br>
-using clang::analyze_format_string::FormatSpecifier;<br>
-using clang::analyze_format_string::LengthModifier;<br>
-using clang::analyze_format_string::OptionalAmount;<br>
-using clang::analyze_format_string::PositionContext;<br>
-using clang::analyze_format_string::ConversionSpecifier;<br>
-using namespace clang;<br>
-<br>
-// Key function to FormatStringHandler.<br>
-FormatStringHandler::~FormatStringHandler() {}<br>
-<br>
-//===----------------------------------------------------------------------===//<br>
-// Functions for parsing format strings components in both printf and<br>
-// scanf format strings.<br>
-//===----------------------------------------------------------------------===//<br>
-<br>
-OptionalAmount<br>
-clang::analyze_format_string::ParseAmount(const char *&Beg, const char *E) {<br>
- const char *I = Beg;<br>
- UpdateOnReturn <const char*> UpdateBeg(Beg, I);<br>
-<br>
- unsigned accumulator = 0;<br>
- bool hasDigits = false;<br>
-<br>
- for ( ; I != E; ++I) {<br>
- char c = *I;<br>
- if (c >= '0' && c <= '9') {<br>
- hasDigits = true;<br>
- accumulator = (accumulator * 10) + (c - '0');<br>
- continue;<br>
- }<br>
-<br>
- if (hasDigits)<br>
- return OptionalAmount(OptionalAmount::Constant, accumulator, Beg, I - Beg,<br>
- false);<br>
-<br>
- break;<br>
- }<br>
-<br>
- return OptionalAmount();<br>
-}<br>
-<br>
-OptionalAmount<br>
-clang::analyze_format_string::ParseNonPositionAmount(const char *&Beg,<br>
- const char *E,<br>
- unsigned &argIndex) {<br>
- if (*Beg == '*') {<br>
- ++Beg;<br>
- return OptionalAmount(OptionalAmount::Arg, argIndex++, Beg, 0, false);<br>
- }<br>
-<br>
- return ParseAmount(Beg, E);<br>
-}<br>
-<br>
-OptionalAmount<br>
-clang::analyze_format_string::ParsePositionAmount(FormatStringHandler &H,<br>
- const char *Start,<br>
- const char *&Beg,<br>
- const char *E,<br>
- PositionContext p) {<br>
- if (*Beg == '*') {<br>
- const char *I = Beg + 1;<br>
- const OptionalAmount &Amt = ParseAmount(I, E);<br>
-<br>
- if (Amt.getHowSpecified() == OptionalAmount::NotSpecified) {<br>
- H.HandleInvalidPosition(Beg, I - Beg, p);<br>
- return OptionalAmount(false);<br>
- }<br>
-<br>
- if (I == E) {<br>
- // No more characters left?<br>
- H.HandleIncompleteSpecifier(Start, E - Start);<br>
- return OptionalAmount(false);<br>
- }<br>
-<br>
- assert(Amt.getHowSpecified() == OptionalAmount::Constant);<br>
-<br>
- if (*I == '$') {<br>
- // Handle positional arguments<br>
-<br>
- // Special case: '*0$', since this is an easy mistake.<br>
- if (Amt.getConstantAmount() == 0) {<br>
- H.HandleZeroPosition(Beg, I - Beg + 1);<br>
- return OptionalAmount(false);<br>
- }<br>
-<br>
- const char *Tmp = Beg;<br>
- Beg = ++I;<br>
-<br>
- return OptionalAmount(OptionalAmount::Arg, Amt.getConstantAmount() - 1,<br>
- Tmp, 0, true);<br>
- }<br>
-<br>
- H.HandleInvalidPosition(Beg, I - Beg, p);<br>
- return OptionalAmount(false);<br>
- }<br>
-<br>
- return ParseAmount(Beg, E);<br>
-}<br>
-<br>
-<br>
-bool<br>
-clang::analyze_format_string::ParseFieldWidth(FormatStringHandler &H,<br>
- FormatSpecifier &CS,<br>
- const char *Start,<br>
- const char *&Beg, const char *E,<br>
- unsigned *argIndex) {<br>
- // FIXME: Support negative field widths.<br>
- if (argIndex) {<br>
- CS.setFieldWidth(ParseNonPositionAmount(Beg, E, *argIndex));<br>
- }<br>
- else {<br>
- const OptionalAmount Amt =<br>
- ParsePositionAmount(H, Start, Beg, E,<br>
- analyze_format_string::FieldWidthPos);<br>
-<br>
- if (Amt.isInvalid())<br>
- return true;<br>
- CS.setFieldWidth(Amt);<br>
- }<br>
- return false;<br>
-}<br>
-<br>
-bool<br>
-clang::analyze_format_string::ParseArgPosition(FormatStringHandler &H,<br>
- FormatSpecifier &FS,<br>
- const char *Start,<br>
- const char *&Beg,<br>
- const char *E) {<br>
- const char *I = Beg;<br>
-<br>
- const OptionalAmount &Amt = ParseAmount(I, E);<br>
-<br>
- if (I == E) {<br>
- // No more characters left?<br>
- H.HandleIncompleteSpecifier(Start, E - Start);<br>
- return true;<br>
- }<br>
-<br>
- if (Amt.getHowSpecified() == OptionalAmount::Constant && *(I++) == '$') {<br>
- // Warn that positional arguments are non-standard.<br>
- H.HandlePosition(Start, I - Start);<br>
-<br>
- // Special case: '%0$', since this is an easy mistake.<br>
- if (Amt.getConstantAmount() == 0) {<br>
- H.HandleZeroPosition(Start, I - Start);<br>
- return true;<br>
- }<br>
-<br>
- FS.setArgIndex(Amt.getConstantAmount() - 1);<br>
- FS.setUsesPositionalArg();<br>
- // Update the caller's pointer if we decided to consume<br>
- // these characters.<br>
- Beg = I;<br>
- return false;<br>
- }<br>
-<br>
- return false;<br>
-}<br>
-<br>
-bool<br>
-clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS,<br>
- const char *&I,<br>
- const char *E,<br>
- const LangOptions &LO,<br>
- bool IsScanf) {<br>
- LengthModifier::Kind lmKind = LengthModifier::None;<br>
- const char *lmPosition = I;<br>
- switch (*I) {<br>
- default:<br>
- return false;<br>
- case 'h':<br>
- ++I;<br>
- if (I != E && *I == 'h') {<br>
- ++I;<br>
- lmKind = LengthModifier::AsChar;<br>
- } else {<br>
- lmKind = LengthModifier::AsShort;<br>
- }<br>
- break;<br>
- case 'l':<br>
- ++I;<br>
- if (I != E && *I == 'l') {<br>
- ++I;<br>
- lmKind = LengthModifier::AsLongLong;<br>
- } else {<br>
- lmKind = LengthModifier::AsLong;<br>
- }<br>
- break;<br>
- case 'j': lmKind = LengthModifier::AsIntMax; ++I; break;<br>
- case 'z': lmKind = LengthModifier::AsSizeT; ++I; break;<br>
- case 't': lmKind = LengthModifier::AsPtrDiff; ++I; break;<br>
- case 'L': lmKind = LengthModifier::AsLongDouble; ++I; break;<br>
- case 'q': lmKind = LengthModifier::AsQuad; ++I; break;<br>
- case 'a':<br>
- if (IsScanf && !LO.C99 && !LO.CPlusPlus11) {<br>
- // For scanf in C90, look at the next character to see if this should<br>
- // be parsed as the GNU extension 'a' length modifier. If not, this<br>
- // will be parsed as a conversion specifier.<br>
- ++I;<br>
- if (I != E && (*I == 's' || *I == 'S' || *I == '[')) {<br>
- lmKind = LengthModifier::AsAllocate;<br>
- break;<br>
- }<br>
- --I;<br>
- }<br>
- return false;<br>
- case 'm':<br>
- if (IsScanf) {<br>
- lmKind = LengthModifier::AsMAllocate;<br>
- ++I;<br>
- break;<br>
- }<br>
- return false;<br>
- // printf: AsInt64, AsInt32, AsInt3264<br>
- // scanf: AsInt64<br>
- case 'I':<br>
- if (I + 1 != E && I + 2 != E) {<br>
- if (I[1] == '6' && I[2] == '4') {<br>
- I += 3;<br>
- lmKind = LengthModifier::AsInt64;<br>
- break;<br>
- }<br>
- if (IsScanf)<br>
- return false;<br>
-<br>
- if (I[1] == '3' && I[2] == '2') {<br>
- I += 3;<br>
- lmKind = LengthModifier::AsInt32;<br>
- break;<br>
- }<br>
- }<br>
- ++I;<br>
- lmKind = LengthModifier::AsInt3264;<br>
- break;<br>
- case 'w':<br>
- lmKind = LengthModifier::AsWide; ++I; break;<br>
- }<br>
- LengthModifier lm(lmPosition, lmKind);<br>
- FS.setLengthModifier(lm);<br>
- return true;<br>
-}<br>
-<br>
-bool clang::analyze_format_string::ParseUTF8InvalidSpecifier(<br>
- const char *SpecifierBegin, const char *FmtStrEnd, unsigned &Len) {<br>
- if (SpecifierBegin + 1 >= FmtStrEnd)<br>
- return false;<br>
-<br>
- const llvm::UTF8 *SB =<br>
- reinterpret_cast<const llvm::UTF8 *>(SpecifierBegin + 1);<br>
- const llvm::UTF8 *SE = reinterpret_cast<const llvm::UTF8 *>(FmtStrEnd);<br>
- const char FirstByte = *SB;<br>
-<br>
- // If the invalid specifier is a multibyte UTF-8 string, return the<br>
- // total length accordingly so that the conversion specifier can be<br>
- // properly updated to reflect a complete UTF-8 specifier.<br>
- unsigned NumBytes = llvm::getNumBytesForUTF8(FirstByte);<br>
- if (NumBytes == 1)<br>
- return false;<br>
- if (SB + NumBytes > SE)<br>
- return false;<br>
-<br>
- Len = NumBytes + 1;<br>
- return true;<br>
-}<br>
-<br>
-//===----------------------------------------------------------------------===//<br>
-// Methods on ArgType.<br>
-//===----------------------------------------------------------------------===//<br>
-<br>
-clang::analyze_format_string::ArgType::MatchKind<br>
-ArgType::matchesType(ASTContext &C, QualType argTy) const {<br>
- if (Ptr) {<br>
- // It has to be a pointer.<br>
- const PointerType *PT = argTy->getAs<PointerType>();<br>
- if (!PT)<br>
- return NoMatch;<br>
-<br>
- // We cannot write through a const qualified pointer.<br>
- if (PT->getPointeeType().isConstQualified())<br>
- return NoMatch;<br>
-<br>
- argTy = PT->getPointeeType();<br>
- }<br>
-<br>
- switch (K) {<br>
- case InvalidTy:<br>
- llvm_unreachable("ArgType must be valid");<br>
-<br>
- case UnknownTy:<br>
- return Match;<br>
-<br>
- case AnyCharTy: {<br>
- if (const EnumType *ETy = argTy->getAs<EnumType>()) {<br>
- // If the enum is incomplete we know nothing about the underlying type.<br>
- // Assume that it's 'int'.<br>
- if (!ETy->getDecl()->isComplete())<br>
- return NoMatch;<br>
- argTy = ETy->getDecl()->getIntegerType();<br>
- }<br>
-<br>
- if (const BuiltinType *BT = argTy->getAs<BuiltinType>())<br>
- switch (BT->getKind()) {<br>
- default:<br>
- break;<br>
- case BuiltinType::Char_S:<br>
- case BuiltinType::SChar:<br>
- case BuiltinType::UChar:<br>
- case BuiltinType::Char_U:<br>
- return Match;<br>
- }<br>
- return NoMatch;<br>
- }<br>
-<br>
- case SpecificTy: {<br>
- if (const EnumType *ETy = argTy->getAs<EnumType>()) {<br>
- // If the enum is incomplete we know nothing about the underlying type.<br>
- // Assume that it's 'int'.<br>
- if (!ETy->getDecl()->isComplete())<br>
- argTy = C.IntTy;<br>
- else<br>
- argTy = ETy->getDecl()->getIntegerType();<br>
- }<br>
- argTy = C.getCanonicalType(argTy).getUnqualifiedType();<br>
-<br>
- if (T == argTy)<br>
- return Match;<br>
- // Check for "compatible types".<br>
- if (const BuiltinType *BT = argTy->getAs<BuiltinType>())<br>
- switch (BT->getKind()) {<br>
- default:<br>
- break;<br>
- case BuiltinType::Char_S:<br>
- case BuiltinType::SChar:<br>
- case BuiltinType::Char_U:<br>
- case BuiltinType::UChar:<br>
- return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match<br>
- : NoMatch;<br>
- case BuiltinType::Short:<br>
- return T == C.UnsignedShortTy ? Match : NoMatch;<br>
- case BuiltinType::UShort:<br>
- return T == C.ShortTy ? Match : NoMatch;<br>
- case BuiltinType::Int:<br>
- return T == C.UnsignedIntTy ? Match : NoMatch;<br>
- case BuiltinType::UInt:<br>
- return T == C.IntTy ? Match : NoMatch;<br>
- case BuiltinType::Long:<br>
- return T == C.UnsignedLongTy ? Match : NoMatch;<br>
- case BuiltinType::ULong:<br>
- return T == C.LongTy ? Match : NoMatch;<br>
- case BuiltinType::LongLong:<br>
- return T == C.UnsignedLongLongTy ? Match : NoMatch;<br>
- case BuiltinType::ULongLong:<br>
- return T == C.LongLongTy ? Match : NoMatch;<br>
- }<br>
- return NoMatch;<br>
- }<br>
-<br>
- case CStrTy: {<br>
- const PointerType *PT = argTy->getAs<PointerType>();<br>
- if (!PT)<br>
- return NoMatch;<br>
- QualType pointeeTy = PT->getPointeeType();<br>
- if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>())<br>
- switch (BT->getKind()) {<br>
- case BuiltinType::Void:<br>
- case BuiltinType::Char_U:<br>
- case BuiltinType::UChar:<br>
- case BuiltinType::Char_S:<br>
- case BuiltinType::SChar:<br>
- return Match;<br>
- default:<br>
- break;<br>
- }<br>
-<br>
- return NoMatch;<br>
- }<br>
-<br>
- case WCStrTy: {<br>
- const PointerType *PT = argTy->getAs<PointerType>();<br>
- if (!PT)<br>
- return NoMatch;<br>
- QualType pointeeTy =<br>
- C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType();<br>
- return pointeeTy == C.getWideCharType() ? Match : NoMatch;<br>
- }<br>
-<br>
- case WIntTy: {<br>
- QualType WInt = C.getCanonicalType(C.getWIntType()).getUnqualifiedType();<br>
-<br>
- if (C.getCanonicalType(argTy).getUnqualifiedType() == WInt)<br>
- return Match;<br>
-<br>
- QualType PromoArg = argTy->isPromotableIntegerType()<br>
- ? C.getPromotedIntegerType(argTy)<br>
- : argTy;<br>
- PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType();<br>
-<br>
- // If the promoted argument is the corresponding signed type of the<br>
- // wint_t type, then it should match.<br>
- if (PromoArg->hasSignedIntegerRepresentation() &&<br>
- C.getCorrespondingUnsignedType(PromoArg) == WInt)<br>
- return Match;<br>
-<br>
- return WInt == PromoArg ? Match : NoMatch;<br>
- }<br>
-<br>
- case CPointerTy:<br>
- if (argTy->isVoidPointerType()) {<br>
- return Match;<br>
- } if (argTy->isPointerType() || argTy->isObjCObjectPointerType() ||<br>
- argTy->isBlockPointerType() || argTy->isNullPtrType()) {<br>
- return NoMatchPedantic;<br>
- } else {<br>
- return NoMatch;<br>
- }<br>
-<br>
- case ObjCPointerTy: {<br>
- if (argTy->getAs<ObjCObjectPointerType>() ||<br>
- argTy->getAs<BlockPointerType>())<br>
- return Match;<br>
-<br>
- // Handle implicit toll-free bridging.<br>
- if (const PointerType *PT = argTy->getAs<PointerType>()) {<br>
- // Things such as CFTypeRef are really just opaque pointers<br>
- // to C structs representing CF types that can often be bridged<br>
- // to Objective-C objects. Since the compiler doesn't know which<br>
- // structs can be toll-free bridged, we just accept them all.<br>
- QualType pointee = PT->getPointeeType();<br>
- if (pointee->getAsStructureType() || pointee->isVoidType())<br>
- return Match;<br>
- }<br>
- return NoMatch;<br>
- }<br>
- }<br>
-<br>
- llvm_unreachable("Invalid ArgType Kind!");<br>
-}<br>
-<br>
-QualType ArgType::getRepresentativeType(ASTContext &C) const {<br>
- QualType Res;<br>
- switch (K) {<br>
- case InvalidTy:<br>
- llvm_unreachable("No representative type for Invalid ArgType");<br>
- case UnknownTy:<br>
- llvm_unreachable("No representative type for Unknown ArgType");<br>
- case AnyCharTy:<br>
- Res = C.CharTy;<br>
- break;<br>
- case SpecificTy:<br>
- Res = T;<br>
- break;<br>
- case CStrTy:<br>
- Res = C.getPointerType(C.CharTy);<br>
- break;<br>
- case WCStrTy:<br>
- Res = C.getPointerType(C.getWideCharType());<br>
- break;<br>
- case ObjCPointerTy:<br>
- Res = C.ObjCBuiltinIdTy;<br>
- break;<br>
- case CPointerTy:<br>
- Res = C.VoidPtrTy;<br>
- break;<br>
- case WIntTy: {<br>
- Res = C.getWIntType();<br>
- break;<br>
- }<br>
- }<br>
-<br>
- if (Ptr)<br>
- Res = C.getPointerType(Res);<br>
- return Res;<br>
-}<br>
-<br>
-std::string ArgType::getRepresentativeTypeName(ASTContext &C) const {<br>
- std::string S = getRepresentativeType(C).getAsString();<br>
-<br>
- std::string Alias;<br>
- if (Name) {<br>
- // Use a specific name for this type, e.g. "size_t".<br>
- Alias = Name;<br>
- if (Ptr) {<br>
- // If ArgType is actually a pointer to T, append an asterisk.<br>
- Alias += (Alias[Alias.size()-1] == '*') ? "*" : " *";<br>
- }<br>
- // If Alias is the same as the underlying type, e.g. wchar_t, then drop it.<br>
- if (S == Alias)<br>
- Alias.clear();<br>
- }<br>
-<br>
- if (!Alias.empty())<br>
- return std::string("'") + Alias + "' (aka '" + S + "')";<br>
- return std::string("'") + S + "'";<br>
-}<br>
-<br>
-<br>
-//===----------------------------------------------------------------------===//<br>
-// Methods on OptionalAmount.<br>
-//===----------------------------------------------------------------------===//<br>
-<br>
-ArgType<br>
-analyze_format_string::OptionalAmount::getArgType(ASTContext &Ctx) const {<br>
- return Ctx.IntTy;<br>
-}<br>
-<br>
-//===----------------------------------------------------------------------===//<br>
-// Methods on LengthModifier.<br>
-//===----------------------------------------------------------------------===//<br>
-<br>
-const char *<br>
-analyze_format_string::LengthModifier::toString() const {<br>
- switch (kind) {<br>
- case AsChar:<br>
- return "hh";<br>
- case AsShort:<br>
- return "h";<br>
- case AsLong: // or AsWideChar<br>
- return "l";<br>
- case AsLongLong:<br>
- return "ll";<br>
- case AsQuad:<br>
- return "q";<br>
- case AsIntMax:<br>
- return "j";<br>
- case AsSizeT:<br>
- return "z";<br>
- case AsPtrDiff:<br>
- return "t";<br>
- case AsInt32:<br>
- return "I32";<br>
- case AsInt3264:<br>
- return "I";<br>
- case AsInt64:<br>
- return "I64";<br>
- case AsLongDouble:<br>
- return "L";<br>
- case AsAllocate:<br>
- return "a";<br>
- case AsMAllocate:<br>
- return "m";<br>
- case AsWide:<br>
- return "w";<br>
- case None:<br>
- return "";<br>
- }<br>
- return nullptr;<br>
-}<br>
-<br>
-//===----------------------------------------------------------------------===//<br>
-// Methods on ConversionSpecifier.<br>
-//===----------------------------------------------------------------------===//<br>
-<br>
-const char *ConversionSpecifier::toString() const {<br>
- switch (kind) {<br>
- case dArg: return "d";<br>
- case DArg: return "D";<br>
- case iArg: return "i";<br>
- case oArg: return "o";<br>
- case OArg: return "O";<br>
- case uArg: return "u";<br>
- case UArg: return "U";<br>
- case xArg: return "x";<br>
- case XArg: return "X";<br>
- case fArg: return "f";<br>
- case FArg: return "F";<br>
- case eArg: return "e";<br>
- case EArg: return "E";<br>
- case gArg: return "g";<br>
- case GArg: return "G";<br>
- case aArg: return "a";<br>
- case AArg: return "A";<br>
- case cArg: return "c";<br>
- case sArg: return "s";<br>
- case pArg: return "p";<br>
- case PArg:<br>
- return "P";<br>
- case nArg: return "n";<br>
- case PercentArg: return "%";<br>
- case ScanListArg: return "[";<br>
- case InvalidSpecifier: return nullptr;<br>
-<br>
- // POSIX unicode extensions.<br>
- case CArg: return "C";<br>
- case SArg: return "S";<br>
-<br>
- // Objective-C specific specifiers.<br>
- case ObjCObjArg: return "@";<br>
-<br>
- // FreeBSD kernel specific specifiers.<br>
- case FreeBSDbArg: return "b";<br>
- case FreeBSDDArg: return "D";<br>
- case FreeBSDrArg: return "r";<br>
- case FreeBSDyArg: return "y";<br>
-<br>
- // GlibC specific specifiers.<br>
- case PrintErrno: return "m";<br>
-<br>
- // MS specific specifiers.<br>
- case ZArg: return "Z";<br>
- }<br>
- return nullptr;<br>
-}<br>
-<br>
-Optional<ConversionSpecifier><br>
-ConversionSpecifier::getStandardSpecifier() const {<br>
- ConversionSpecifier::Kind NewKind;<br>
-<br>
- switch (getKind()) {<br>
- default:<br>
- return None;<br>
- case DArg:<br>
- NewKind = dArg;<br>
- break;<br>
- case UArg:<br>
- NewKind = uArg;<br>
- break;<br>
- case OArg:<br>
- NewKind = oArg;<br>
- break;<br>
- }<br>
-<br>
- ConversionSpecifier FixedCS(*this);<br>
- FixedCS.setKind(NewKind);<br>
- return FixedCS;<br>
-}<br>
-<br>
-//===----------------------------------------------------------------------===//<br>
-// Methods on OptionalAmount.<br>
-//===----------------------------------------------------------------------===//<br>
-<br>
-void OptionalAmount::toString(raw_ostream &os) const {<br>
- switch (hs) {<br>
- case Invalid:<br>
- case NotSpecified:<br>
- return;<br>
- case Arg:<br>
- if (UsesDotPrefix)<br>
- os << ".";<br>
- if (usesPositionalArg())<br>
- os << "*" << getPositionalArgIndex() << "$";<br>
- else<br>
- os << "*";<br>
- break;<br>
- case Constant:<br>
- if (UsesDotPrefix)<br>
- os << ".";<br>
- os << amt;<br>
- break;<br>
- }<br>
-}<br>
-<br>
-bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const {<br>
- switch (LM.getKind()) {<br>
- case LengthModifier::None:<br>
- return true;<br>
-<br>
- // Handle most integer flags<br>
- case LengthModifier::AsShort:<br>
- if (Target.getTriple().isOSMSVCRT()) {<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::cArg:<br>
- case ConversionSpecifier::CArg:<br>
- case ConversionSpecifier::sArg:<br>
- case ConversionSpecifier::SArg:<br>
- case ConversionSpecifier::ZArg:<br>
- return true;<br>
- default:<br>
- break;<br>
- }<br>
- }<br>
- LLVM_FALLTHROUGH;<br>
- case LengthModifier::AsChar:<br>
- case LengthModifier::AsLongLong:<br>
- case LengthModifier::AsQuad:<br>
- case LengthModifier::AsIntMax:<br>
- case LengthModifier::AsSizeT:<br>
- case LengthModifier::AsPtrDiff:<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::dArg:<br>
- case ConversionSpecifier::DArg:<br>
- case ConversionSpecifier::iArg:<br>
- case ConversionSpecifier::oArg:<br>
- case ConversionSpecifier::OArg:<br>
- case ConversionSpecifier::uArg:<br>
- case ConversionSpecifier::UArg:<br>
- case ConversionSpecifier::xArg:<br>
- case ConversionSpecifier::XArg:<br>
- case ConversionSpecifier::nArg:<br>
- return true;<br>
- case ConversionSpecifier::FreeBSDrArg:<br>
- case ConversionSpecifier::FreeBSDyArg:<br>
- return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS4();<br>
- default:<br>
- return false;<br>
- }<br>
-<br>
- // Handle 'l' flag<br>
- case LengthModifier::AsLong: // or AsWideChar<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::dArg:<br>
- case ConversionSpecifier::DArg:<br>
- case ConversionSpecifier::iArg:<br>
- case ConversionSpecifier::oArg:<br>
- case ConversionSpecifier::OArg:<br>
- case ConversionSpecifier::uArg:<br>
- case ConversionSpecifier::UArg:<br>
- case ConversionSpecifier::xArg:<br>
- case ConversionSpecifier::XArg:<br>
- case ConversionSpecifier::aArg:<br>
- case ConversionSpecifier::AArg:<br>
- case ConversionSpecifier::fArg:<br>
- case ConversionSpecifier::FArg:<br>
- case ConversionSpecifier::eArg:<br>
- case ConversionSpecifier::EArg:<br>
- case ConversionSpecifier::gArg:<br>
- case ConversionSpecifier::GArg:<br>
- case ConversionSpecifier::nArg:<br>
- case ConversionSpecifier::cArg:<br>
- case ConversionSpecifier::sArg:<br>
- case ConversionSpecifier::ScanListArg:<br>
- case ConversionSpecifier::ZArg:<br>
- return true;<br>
- case ConversionSpecifier::FreeBSDrArg:<br>
- case ConversionSpecifier::FreeBSDyArg:<br>
- return Target.getTriple().isOSFreeBSD() || Target.getTriple().isPS4();<br>
- default:<br>
- return false;<br>
- }<br>
-<br>
- case LengthModifier::AsLongDouble:<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::aArg:<br>
- case ConversionSpecifier::AArg:<br>
- case ConversionSpecifier::fArg:<br>
- case ConversionSpecifier::FArg:<br>
- case ConversionSpecifier::eArg:<br>
- case ConversionSpecifier::EArg:<br>
- case ConversionSpecifier::gArg:<br>
- case ConversionSpecifier::GArg:<br>
- return true;<br>
- // GNU libc extension.<br>
- case ConversionSpecifier::dArg:<br>
- case ConversionSpecifier::iArg:<br>
- case ConversionSpecifier::oArg:<br>
- case ConversionSpecifier::uArg:<br>
- case ConversionSpecifier::xArg:<br>
- case ConversionSpecifier::XArg:<br>
- return !Target.getTriple().isOSDarwin() &&<br>
- !Target.getTriple().isOSWindows();<br>
- default:<br>
- return false;<br>
- }<br>
-<br>
- case LengthModifier::AsAllocate:<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::sArg:<br>
- case ConversionSpecifier::SArg:<br>
- case ConversionSpecifier::ScanListArg:<br>
- return true;<br>
- default:<br>
- return false;<br>
- }<br>
-<br>
- case LengthModifier::AsMAllocate:<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::cArg:<br>
- case ConversionSpecifier::CArg:<br>
- case ConversionSpecifier::sArg:<br>
- case ConversionSpecifier::SArg:<br>
- case ConversionSpecifier::ScanListArg:<br>
- return true;<br>
- default:<br>
- return false;<br>
- }<br>
- case LengthModifier::AsInt32:<br>
- case LengthModifier::AsInt3264:<br>
- case LengthModifier::AsInt64:<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::dArg:<br>
- case ConversionSpecifier::iArg:<br>
- case ConversionSpecifier::oArg:<br>
- case ConversionSpecifier::uArg:<br>
- case ConversionSpecifier::xArg:<br>
- case ConversionSpecifier::XArg:<br>
- return Target.getTriple().isOSMSVCRT();<br>
- default:<br>
- return false;<br>
- }<br>
- case LengthModifier::AsWide:<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::cArg:<br>
- case ConversionSpecifier::CArg:<br>
- case ConversionSpecifier::sArg:<br>
- case ConversionSpecifier::SArg:<br>
- case ConversionSpecifier::ZArg:<br>
- return Target.getTriple().isOSMSVCRT();<br>
- default:<br>
- return false;<br>
- }<br>
- }<br>
- llvm_unreachable("Invalid LengthModifier Kind!");<br>
-}<br>
-<br>
-bool FormatSpecifier::hasStandardLengthModifier() const {<br>
- switch (LM.getKind()) {<br>
- case LengthModifier::None:<br>
- case LengthModifier::AsChar:<br>
- case LengthModifier::AsShort:<br>
- case LengthModifier::AsLong:<br>
- case LengthModifier::AsLongLong:<br>
- case LengthModifier::AsIntMax:<br>
- case LengthModifier::AsSizeT:<br>
- case LengthModifier::AsPtrDiff:<br>
- case LengthModifier::AsLongDouble:<br>
- return true;<br>
- case LengthModifier::AsAllocate:<br>
- case LengthModifier::AsMAllocate:<br>
- case LengthModifier::AsQuad:<br>
- case LengthModifier::AsInt32:<br>
- case LengthModifier::AsInt3264:<br>
- case LengthModifier::AsInt64:<br>
- case LengthModifier::AsWide:<br>
- return false;<br>
- }<br>
- llvm_unreachable("Invalid LengthModifier Kind!");<br>
-}<br>
-<br>
-bool FormatSpecifier::hasStandardConversionSpecifier(<br>
- const LangOptions &LangOpt) const {<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::cArg:<br>
- case ConversionSpecifier::dArg:<br>
- case ConversionSpecifier::iArg:<br>
- case ConversionSpecifier::oArg:<br>
- case ConversionSpecifier::uArg:<br>
- case ConversionSpecifier::xArg:<br>
- case ConversionSpecifier::XArg:<br>
- case ConversionSpecifier::fArg:<br>
- case ConversionSpecifier::FArg:<br>
- case ConversionSpecifier::eArg:<br>
- case ConversionSpecifier::EArg:<br>
- case ConversionSpecifier::gArg:<br>
- case ConversionSpecifier::GArg:<br>
- case ConversionSpecifier::aArg:<br>
- case ConversionSpecifier::AArg:<br>
- case ConversionSpecifier::sArg:<br>
- case ConversionSpecifier::pArg:<br>
- case ConversionSpecifier::nArg:<br>
- case ConversionSpecifier::ObjCObjArg:<br>
- case ConversionSpecifier::ScanListArg:<br>
- case ConversionSpecifier::PercentArg:<br>
- case ConversionSpecifier::PArg:<br>
- return true;<br>
- case ConversionSpecifier::CArg:<br>
- case ConversionSpecifier::SArg:<br>
- return LangOpt.ObjC;<br>
- case ConversionSpecifier::InvalidSpecifier:<br>
- case ConversionSpecifier::FreeBSDbArg:<br>
- case ConversionSpecifier::FreeBSDDArg:<br>
- case ConversionSpecifier::FreeBSDrArg:<br>
- case ConversionSpecifier::FreeBSDyArg:<br>
- case ConversionSpecifier::PrintErrno:<br>
- case ConversionSpecifier::DArg:<br>
- case ConversionSpecifier::OArg:<br>
- case ConversionSpecifier::UArg:<br>
- case ConversionSpecifier::ZArg:<br>
- return false;<br>
- }<br>
- llvm_unreachable("Invalid ConversionSpecifier Kind!");<br>
-}<br>
-<br>
-bool FormatSpecifier::hasStandardLengthConversionCombination() const {<br>
- if (LM.getKind() == LengthModifier::AsLongDouble) {<br>
- switch(CS.getKind()) {<br>
- case ConversionSpecifier::dArg:<br>
- case ConversionSpecifier::iArg:<br>
- case ConversionSpecifier::oArg:<br>
- case ConversionSpecifier::uArg:<br>
- case ConversionSpecifier::xArg:<br>
- case ConversionSpecifier::XArg:<br>
- return false;<br>
- default:<br>
- return true;<br>
- }<br>
- }<br>
- return true;<br>
-}<br>
-<br>
-Optional<LengthModifier> FormatSpecifier::getCorrectedLengthModifier() const {<br>
- if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) {<br>
- if (LM.getKind() == LengthModifier::AsLongDouble ||<br>
- LM.getKind() == LengthModifier::AsQuad) {<br>
- LengthModifier FixedLM(LM);<br>
- FixedLM.setKind(LengthModifier::AsLongLong);<br>
- return FixedLM;<br>
- }<br>
- }<br>
-<br>
- return None;<br>
-}<br>
-<br>
-bool FormatSpecifier::namedTypeToLengthModifier(QualType QT,<br>
- LengthModifier &LM) {<br>
- assert(isa<TypedefType>(QT) && "Expected a TypedefType");<br>
- const TypedefNameDecl *Typedef = cast<TypedefType>(QT)->getDecl();<br>
-<br>
- for (;;) {<br>
- const IdentifierInfo *Identifier = Typedef->getIdentifier();<br>
- if (Identifier->getName() == "size_t") {<br>
- LM.setKind(LengthModifier::AsSizeT);<br>
- return true;<br>
- } else if (Identifier->getName() == "ssize_t") {<br>
- // Not C99, but common in Unix.<br>
- LM.setKind(LengthModifier::AsSizeT);<br>
- return true;<br>
- } else if (Identifier->getName() == "intmax_t") {<br>
- LM.setKind(LengthModifier::AsIntMax);<br>
- return true;<br>
- } else if (Identifier->getName() == "uintmax_t") {<br>
- LM.setKind(LengthModifier::AsIntMax);<br>
- return true;<br>
- } else if (Identifier->getName() == "ptrdiff_t") {<br>
- LM.setKind(LengthModifier::AsPtrDiff);<br>
- return true;<br>
- }<br>
-<br>
- QualType T = Typedef->getUnderlyingType();<br>
- if (!isa<TypedefType>(T))<br>
- break;<br>
-<br>
- Typedef = cast<TypedefType>(T)->getDecl();<br>
- }<br>
- return false;<br>
-}<br>
<br>
Removed: cfe/trunk/lib/Analysis/FormatStringParsing.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/FormatStringParsing.h?rev=345970&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/FormatStringParsing.h?rev=345970&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Analysis/FormatStringParsing.h (original)<br>
+++ cfe/trunk/lib/Analysis/FormatStringParsing.h (removed)<br>
@@ -1,79 +0,0 @@<br>
-#ifndef LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H<br>
-#define LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H<br>
-<br>
-#include "clang/AST/ASTContext.h"<br>
-#include "clang/AST/Type.h"<br>
-#include "clang/Analysis/Analyses/FormatString.h"<br>
-<br>
-namespace clang {<br>
-<br>
-class LangOptions;<br>
-<br>
-template <typename T><br>
-class UpdateOnReturn {<br>
- T &ValueToUpdate;<br>
- const T &ValueToCopy;<br>
-public:<br>
- UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)<br>
- : ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}<br>
-<br>
- ~UpdateOnReturn() {<br>
- ValueToUpdate = ValueToCopy;<br>
- }<br>
-};<br>
-<br>
-namespace analyze_format_string {<br>
-<br>
-OptionalAmount ParseAmount(const char *&Beg, const char *E);<br>
-OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,<br>
- unsigned &argIndex);<br>
-<br>
-OptionalAmount ParsePositionAmount(FormatStringHandler &H,<br>
- const char *Start, const char *&Beg,<br>
- const char *E, PositionContext p);<br>
-<br>
-bool ParseFieldWidth(FormatStringHandler &H,<br>
- FormatSpecifier &CS,<br>
- const char *Start, const char *&Beg, const char *E,<br>
- unsigned *argIndex);<br>
-<br>
-bool ParseArgPosition(FormatStringHandler &H,<br>
- FormatSpecifier &CS, const char *Start,<br>
- const char *&Beg, const char *E);<br>
-<br>
-/// Returns true if a LengthModifier was parsed and installed in the<br>
-/// FormatSpecifier& argument, and false otherwise.<br>
-bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const char *E,<br>
- const LangOptions &LO, bool IsScanf = false);<br>
-<br>
-/// Returns true if the invalid specifier in \p SpecifierBegin is a UTF-8<br>
-/// string; check that it won't go further than \p FmtStrEnd and write<br>
-/// up the total size in \p Len.<br>
-bool ParseUTF8InvalidSpecifier(const char *SpecifierBegin,<br>
- const char *FmtStrEnd, unsigned &Len);<br>
-<br>
-template <typename T> class SpecifierResult {<br>
- T FS;<br>
- const char *Start;<br>
- bool Stop;<br>
-public:<br>
- SpecifierResult(bool stop = false)<br>
- : Start(nullptr), Stop(stop) {}<br>
- SpecifierResult(const char *start,<br>
- const T &fs)<br>
- : FS(fs), Start(start), Stop(false) {}<br>
-<br>
- const char *getStart() const { return Start; }<br>
- bool shouldStop() const { return Stop; }<br>
- bool hasValue() const { return Start != nullptr; }<br>
- const T &getValue() const {<br>
- assert(hasValue());<br>
- return FS;<br>
- }<br>
- const T &getValue() { return FS; }<br>
-};<br>
-<br>
-} // end analyze_format_string namespace<br>
-} // end clang namespace<br>
-<br>
-#endif<br>
<br>
Removed: cfe/trunk/lib/Analysis/OSLog.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/OSLog.cpp?rev=345970&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/OSLog.cpp?rev=345970&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Analysis/OSLog.cpp (original)<br>
+++ cfe/trunk/lib/Analysis/OSLog.cpp (removed)<br>
@@ -1,203 +0,0 @@<br>
-// TODO: header template<br>
-<br>
-#include "clang/Analysis/Analyses/OSLog.h"<br>
-#include "clang/AST/Attr.h"<br>
-#include "clang/AST/Decl.h"<br>
-#include "clang/AST/DeclCXX.h"<br>
-#include "clang/AST/ExprObjC.h"<br>
-#include "clang/Analysis/Analyses/FormatString.h"<br>
-#include "clang/Basic/Builtins.h"<br>
-#include "llvm/ADT/SmallBitVector.h"<br>
-<br>
-using namespace clang;<br>
-<br>
-using clang::analyze_os_log::OSLogBufferItem;<br>
-using clang::analyze_os_log::OSLogBufferLayout;<br>
-<br>
-namespace {<br>
-class OSLogFormatStringHandler<br>
- : public analyze_format_string::FormatStringHandler {<br>
-private:<br>
- struct ArgData {<br>
- const Expr *E = nullptr;<br>
- Optional<OSLogBufferItem::Kind> Kind;<br>
- Optional<unsigned> Size;<br>
- Optional<const Expr *> Count;<br>
- Optional<const Expr *> Precision;<br>
- Optional<const Expr *> FieldWidth;<br>
- unsigned char Flags = 0;<br>
- };<br>
- SmallVector<ArgData, 4> ArgsData;<br>
- ArrayRef<const Expr *> Args;<br>
-<br>
- OSLogBufferItem::Kind<br>
- getKind(analyze_format_string::ConversionSpecifier::Kind K) {<br>
- switch (K) {<br>
- case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s"<br>
- return OSLogBufferItem::StringKind;<br>
- case clang::analyze_format_string::ConversionSpecifier::SArg: // "%S"<br>
- return OSLogBufferItem::WideStringKind;<br>
- case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"<br>
- return OSLogBufferItem::PointerKind;<br>
- case clang::analyze_format_string::ConversionSpecifier::ObjCObjArg: // "%@"<br>
- return OSLogBufferItem::ObjCObjKind;<br>
- case clang::analyze_format_string::ConversionSpecifier::PrintErrno: // "%m"<br>
- return OSLogBufferItem::ErrnoKind;<br>
- default:<br>
- return OSLogBufferItem::ScalarKind;<br>
- }<br>
- }<br>
- }<br>
-<br>
-public:<br>
- OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) {<br>
- ArgsData.reserve(Args.size());<br>
- }<br>
-<br>
- virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,<br>
- const char *StartSpecifier,<br>
- unsigned SpecifierLen) {<br>
- if (!FS.consumesDataArgument() &&<br>
- FS.getConversionSpecifier().getKind() !=<br>
- clang::analyze_format_string::ConversionSpecifier::PrintErrno)<br>
- return true;<br>
-<br>
- ArgsData.emplace_back();<br>
- unsigned ArgIndex = FS.getArgIndex();<br>
- if (ArgIndex < Args.size())<br>
- ArgsData.back().E = Args[ArgIndex];<br>
-<br>
- // First get the Kind<br>
- ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind());<br>
- if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind &&<br>
- !ArgsData.back().E) {<br>
- // missing argument<br>
- ArgsData.pop_back();<br>
- return false;<br>
- }<br>
-<br>
- switch (FS.getConversionSpecifier().getKind()) {<br>
- case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s"<br>
- case clang::analyze_format_string::ConversionSpecifier::SArg: { // "%S"<br>
- auto &precision = FS.getPrecision();<br>
- switch (precision.getHowSpecified()) {<br>
- case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%s"<br>
- break;<br>
- case clang::analyze_format_string::OptionalAmount::Constant: // "%.16s"<br>
- ArgsData.back().Size = precision.getConstantAmount();<br>
- break;<br>
- case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s"<br>
- ArgsData.back().Count = Args[precision.getArgIndex()];<br>
- break;<br>
- case clang::analyze_format_string::OptionalAmount::Invalid:<br>
- return false;<br>
- }<br>
- break;<br>
- }<br>
- case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"<br>
- auto &precision = FS.getPrecision();<br>
- switch (precision.getHowSpecified()) {<br>
- case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%P"<br>
- return false; // length must be supplied with pointer format specifier<br>
- case clang::analyze_format_string::OptionalAmount::Constant: // "%.16P"<br>
- ArgsData.back().Size = precision.getConstantAmount();<br>
- break;<br>
- case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P"<br>
- ArgsData.back().Count = Args[precision.getArgIndex()];<br>
- break;<br>
- case clang::analyze_format_string::OptionalAmount::Invalid:<br>
- return false;<br>
- }<br>
- break;<br>
- }<br>
- default:<br>
- if (FS.getPrecision().hasDataArgument()) {<br>
- ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];<br>
- }<br>
- break;<br>
- }<br>
- if (FS.getFieldWidth().hasDataArgument()) {<br>
- ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];<br>
- }<br>
-<br>
- if (FS.isPrivate()) {<br>
- ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;<br>
- }<br>
- if (FS.isPublic()) {<br>
- ArgsData.back().Flags |= OSLogBufferItem::IsPublic;<br>
- }<br>
- return true;<br>
- }<br>
-<br>
- void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {<br>
- Layout.Items.clear();<br>
- for (auto &Data : ArgsData) {<br>
- if (Data.FieldWidth) {<br>
- CharUnits Size = Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType());<br>
- Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.FieldWidth,<br>
- Size, 0);<br>
- }<br>
- if (Data.Precision) {<br>
- CharUnits Size = Ctx.getTypeSizeInChars((*Data.Precision)->getType());<br>
- Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.Precision,<br>
- Size, 0);<br>
- }<br>
- if (Data.Count) {<br>
- // "%.*P" has an extra "count" that we insert before the argument.<br>
- CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType());<br>
- Layout.Items.emplace_back(OSLogBufferItem::CountKind, *Data.Count, Size,<br>
- 0);<br>
- }<br>
- if (Data.Size)<br>
- Layout.Items.emplace_back(Ctx, CharUnits::fromQuantity(*Data.Size),<br>
- Data.Flags);<br>
- if (Data.Kind) {<br>
- CharUnits Size;<br>
- if (*Data.Kind == OSLogBufferItem::ErrnoKind)<br>
- Size = CharUnits::Zero();<br>
- else<br>
- Size = Ctx.getTypeSizeInChars(Data.E->getType());<br>
- Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags);<br>
- } else {<br>
- auto Size = Ctx.getTypeSizeInChars(Data.E->getType());<br>
- Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E, Size,<br>
- Data.Flags);<br>
- }<br>
- }<br>
- }<br>
-};<br>
-} // end anonymous namespace<br>
-<br>
-bool clang::analyze_os_log::computeOSLogBufferLayout(<br>
- ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {<br>
- ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() + E->getNumArgs());<br>
-<br>
- const Expr *StringArg;<br>
- ArrayRef<const Expr *> VarArgs;<br>
- switch (E->getBuiltinCallee()) {<br>
- case Builtin::BI__builtin_os_log_format_buffer_size:<br>
- assert(E->getNumArgs() >= 1 &&<br>
- "__builtin_os_log_format_buffer_size takes at least 1 argument");<br>
- StringArg = E->getArg(0);<br>
- VarArgs = Args.slice(1);<br>
- break;<br>
- case Builtin::BI__builtin_os_log_format:<br>
- assert(E->getNumArgs() >= 2 &&<br>
- "__builtin_os_log_format takes at least 2 arguments");<br>
- StringArg = E->getArg(1);<br>
- VarArgs = Args.slice(2);<br>
- break;<br>
- default:<br>
- llvm_unreachable("non-os_log builtin passed to computeOSLogBufferLayout");<br>
- }<br>
-<br>
- const StringLiteral *Lit = cast<StringLiteral>(StringArg->IgnoreParenCasts());<br>
- assert(Lit && (Lit->isAscii() || Lit->isUTF8()));<br>
- StringRef Data = Lit->getString();<br>
- OSLogFormatStringHandler H(VarArgs);<br>
- ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(),<br>
- Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false);<br>
-<br>
- H.computeLayout(Ctx, Layout);<br>
- return true;<br>
-}<br>
<br>
Removed: cfe/trunk/lib/Analysis/PrintfFormatString.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PrintfFormatString.cpp?rev=345970&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/PrintfFormatString.cpp?rev=345970&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Analysis/PrintfFormatString.cpp (original)<br>
+++ cfe/trunk/lib/Analysis/PrintfFormatString.cpp (removed)<br>
@@ -1,1029 +0,0 @@<br>
-//== PrintfFormatString.cpp - Analysis of printf format strings --*- C++ -*-==//<br>
-//<br>
-// The LLVM Compiler Infrastructure<br>
-//<br>
-// This file is distributed under the University of Illinois Open Source<br>
-// License. See LICENSE.TXT for details.<br>
-//<br>
-//===----------------------------------------------------------------------===//<br>
-//<br>
-// Handling of format string in printf and friends. The structure of format<br>
-// strings for fprintf() are described in C99 7.19.6.1.<br>
-//<br>
-//===----------------------------------------------------------------------===//<br>
-<br>
-#include "clang/Analysis/Analyses/FormatString.h"<br>
-#include "clang/Analysis/Analyses/OSLog.h"<br>
-#include "FormatStringParsing.h"<br>
-#include "clang/Basic/TargetInfo.h"<br>
-<br>
-using clang::analyze_format_string::ArgType;<br>
-using clang::analyze_format_string::FormatStringHandler;<br>
-using clang::analyze_format_string::LengthModifier;<br>
-using clang::analyze_format_string::OptionalAmount;<br>
-using clang::analyze_format_string::ConversionSpecifier;<br>
-using clang::analyze_printf::PrintfSpecifier;<br>
-<br>
-using namespace clang;<br>
-<br>
-typedef clang::analyze_format_string::SpecifierResult<PrintfSpecifier><br>
- PrintfSpecifierResult;<br>
-<br>
-//===----------------------------------------------------------------------===//<br>
-// Methods for parsing format strings.<br>
-//===----------------------------------------------------------------------===//<br>
-<br>
-using analyze_format_string::ParseNonPositionAmount;<br>
-<br>
-static bool ParsePrecision(FormatStringHandler &H, PrintfSpecifier &FS,<br>
- const char *Start, const char *&Beg, const char *E,<br>
- unsigned *argIndex) {<br>
- if (argIndex) {<br>
- FS.setPrecision(ParseNonPositionAmount(Beg, E, *argIndex));<br>
- } else {<br>
- const OptionalAmount Amt = ParsePositionAmount(H, Start, Beg, E,<br>
- analyze_format_string::PrecisionPos);<br>
- if (Amt.isInvalid())<br>
- return true;<br>
- FS.setPrecision(Amt);<br>
- }<br>
- return false;<br>
-}<br>
-<br>
-static bool ParseObjCFlags(FormatStringHandler &H, PrintfSpecifier &FS,<br>
- const char *FlagBeg, const char *E, bool Warn) {<br>
- StringRef Flag(FlagBeg, E - FlagBeg);<br>
- // Currently there is only one flag.<br>
- if (Flag == "tt") {<br>
- FS.setHasObjCTechnicalTerm(FlagBeg);<br>
- return false;<br>
- }<br>
- // Handle either the case of no flag or an invalid flag.<br>
- if (Warn) {<br>
- if (Flag == "")<br>
- H.HandleEmptyObjCModifierFlag(FlagBeg, E - FlagBeg);<br>
- else<br>
- H.HandleInvalidObjCModifierFlag(FlagBeg, E - FlagBeg);<br>
- }<br>
- return true;<br>
-}<br>
-<br>
-static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H,<br>
- const char *&Beg,<br>
- const char *E,<br>
- unsigned &argIndex,<br>
- const LangOptions &LO,<br>
- const TargetInfo &Target,<br>
- bool Warn,<br>
- bool isFreeBSDKPrintf) {<br>
-<br>
- using namespace clang::analyze_format_string;<br>
- using namespace clang::analyze_printf;<br>
-<br>
- const char *I = Beg;<br>
- const char *Start = nullptr;<br>
- UpdateOnReturn <const char*> UpdateBeg(Beg, I);<br>
-<br>
- // Look for a '%' character that indicates the start of a format specifier.<br>
- for ( ; I != E ; ++I) {<br>
- char c = *I;<br>
- if (c == '\0') {<br>
- // Detect spurious null characters, which are likely errors.<br>
- H.HandleNullChar(I);<br>
- return true;<br>
- }<br>
- if (c == '%') {<br>
- Start = I++; // Record the start of the format specifier.<br>
- break;<br>
- }<br>
- }<br>
-<br>
- // No format specifier found?<br>
- if (!Start)<br>
- return false;<br>
-<br>
- if (I == E) {<br>
- // No more characters left?<br>
- if (Warn)<br>
- H.HandleIncompleteSpecifier(Start, E - Start);<br>
- return true;<br>
- }<br>
-<br>
- PrintfSpecifier FS;<br>
- if (ParseArgPosition(H, FS, Start, I, E))<br>
- return true;<br>
-<br>
- if (I == E) {<br>
- // No more characters left?<br>
- if (Warn)<br>
- H.HandleIncompleteSpecifier(Start, E - Start);<br>
- return true;<br>
- }<br>
-<br>
- if (*I == '{') {<br>
- ++I;<br>
- unsigned char PrivacyFlags = 0;<br>
- StringRef MatchedStr;<br>
-<br>
- do {<br>
- StringRef Str(I, E - I);<br>
- std::string Match = "^[\t\n\v\f\r ]*(private|public)[\t\n\v\f\r ]*(,|})";<br>
- llvm::Regex R(Match);<br>
- SmallVector<StringRef, 2> Matches;<br>
-<br>
- if (R.match(Str, &Matches)) {<br>
- MatchedStr = Matches[1];<br>
- I += Matches[0].size();<br>
-<br>
- // Set the privacy flag if the privacy annotation in the<br>
- // comma-delimited segment is at least as strict as the privacy<br>
- // annotations in previous comma-delimited segments.<br>
- if (MatchedStr.equals("private"))<br>
- PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPrivate;<br>
- else if (PrivacyFlags == 0 && MatchedStr.equals("public"))<br>
- PrivacyFlags = clang::analyze_os_log::OSLogBufferItem::IsPublic;<br>
- } else {<br>
- size_t CommaOrBracePos =<br>
- Str.find_if([](char c) { return c == ',' || c == '}'; });<br>
-<br>
- if (CommaOrBracePos == StringRef::npos) {<br>
- // Neither a comma nor the closing brace was found.<br>
- if (Warn)<br>
- H.HandleIncompleteSpecifier(Start, E - Start);<br>
- return true;<br>
- }<br>
-<br>
- I += CommaOrBracePos + 1;<br>
- }<br>
- // Continue until the closing brace is found.<br>
- } while (*(I - 1) == ',');<br>
-<br>
- // Set the privacy flag.<br>
- switch (PrivacyFlags) {<br>
- case 0:<br>
- break;<br>
- case clang::analyze_os_log::OSLogBufferItem::IsPrivate:<br>
- FS.setIsPrivate(MatchedStr.data());<br>
- break;<br>
- case clang::analyze_os_log::OSLogBufferItem::IsPublic:<br>
- FS.setIsPublic(MatchedStr.data());<br>
- break;<br>
- default:<br>
- llvm_unreachable("Unexpected privacy flag value");<br>
- }<br>
- }<br>
-<br>
- // Look for flags (if any).<br>
- bool hasMore = true;<br>
- for ( ; I != E; ++I) {<br>
- switch (*I) {<br>
- default: hasMore = false; break;<br>
- case '\'':<br>
- // FIXME: POSIX specific. Always accept?<br>
- FS.setHasThousandsGrouping(I);<br>
- break;<br>
- case '-': FS.setIsLeftJustified(I); break;<br>
- case '+': FS.setHasPlusPrefix(I); break;<br>
- case ' ': FS.setHasSpacePrefix(I); break;<br>
- case '#': FS.setHasAlternativeForm(I); break;<br>
- case '0': FS.setHasLeadingZeros(I); break;<br>
- }<br>
- if (!hasMore)<br>
- break;<br>
- }<br>
-<br>
- if (I == E) {<br>
- // No more characters left?<br>
- if (Warn)<br>
- H.HandleIncompleteSpecifier(Start, E - Start);<br>
- return true;<br>
- }<br>
-<br>
- // Look for the field width (if any).<br>
- if (ParseFieldWidth(H, FS, Start, I, E,<br>
- FS.usesPositionalArg() ? nullptr : &argIndex))<br>
- return true;<br>
-<br>
- if (I == E) {<br>
- // No more characters left?<br>
- if (Warn)<br>
- H.HandleIncompleteSpecifier(Start, E - Start);<br>
- return true;<br>
- }<br>
-<br>
- // Look for the precision (if any).<br>
- if (*I == '.') {<br>
- ++I;<br>
- if (I == E) {<br>
- if (Warn)<br>
- H.HandleIncompleteSpecifier(Start, E - Start);<br>
- return true;<br>
- }<br>
-<br>
- if (ParsePrecision(H, FS, Start, I, E,<br>
- FS.usesPositionalArg() ? nullptr : &argIndex))<br>
- return true;<br>
-<br>
- if (I == E) {<br>
- // No more characters left?<br>
- if (Warn)<br>
- H.HandleIncompleteSpecifier(Start, E - Start);<br>
- return true;<br>
- }<br>
- }<br>
-<br>
- // Look for the length modifier.<br>
- if (ParseLengthModifier(FS, I, E, LO) && I == E) {<br>
- // No more characters left?<br>
- if (Warn)<br>
- H.HandleIncompleteSpecifier(Start, E - Start);<br>
- return true;<br>
- }<br>
-<br>
- // Look for the Objective-C modifier flags, if any.<br>
- // We parse these here, even if they don't apply to<br>
- // the conversion specifier, and then emit an error<br>
- // later if the conversion specifier isn't '@'. This<br>
- // enables better recovery, and we don't know if<br>
- // these flags are applicable until later.<br>
- const char *ObjCModifierFlagsStart = nullptr,<br>
- *ObjCModifierFlagsEnd = nullptr;<br>
- if (*I == '[') {<br>
- ObjCModifierFlagsStart = I;<br>
- ++I;<br>
- auto flagStart = I;<br>
- for (;; ++I) {<br>
- ObjCModifierFlagsEnd = I;<br>
- if (I == E) {<br>
- if (Warn)<br>
- H.HandleIncompleteSpecifier(Start, E - Start);<br>
- return true;<br>
- }<br>
- // Did we find the closing ']'?<br>
- if (*I == ']') {<br>
- if (ParseObjCFlags(H, FS, flagStart, I, Warn))<br>
- return true;<br>
- ++I;<br>
- break;<br>
- }<br>
- // There are no separators defined yet for multiple<br>
- // Objective-C modifier flags. When those are<br>
- // defined, this is the place to check.<br>
- }<br>
- }<br>
-<br>
- if (*I == '\0') {<br>
- // Detect spurious null characters, which are likely errors.<br>
- H.HandleNullChar(I);<br>
- return true;<br>
- }<br>
-<br>
- // Finally, look for the conversion specifier.<br>
- const char *conversionPosition = I++;<br>
- ConversionSpecifier::Kind k = ConversionSpecifier::InvalidSpecifier;<br>
- switch (*conversionPosition) {<br>
- default:<br>
- break;<br>
- // C99: 7.19.6.1 (section 8).<br>
- case '%': k = ConversionSpecifier::PercentArg; break;<br>
- case 'A': k = ConversionSpecifier::AArg; break;<br>
- case 'E': k = ConversionSpecifier::EArg; break;<br>
- case 'F': k = ConversionSpecifier::FArg; break;<br>
- case 'G': k = ConversionSpecifier::GArg; break;<br>
- case 'X': k = ConversionSpecifier::XArg; break;<br>
- case 'a': k = ConversionSpecifier::aArg; break;<br>
- case 'c': k = ConversionSpecifier::cArg; break;<br>
- case 'd': k = ConversionSpecifier::dArg; break;<br>
- case 'e': k = ConversionSpecifier::eArg; break;<br>
- case 'f': k = ConversionSpecifier::fArg; break;<br>
- case 'g': k = ConversionSpecifier::gArg; break;<br>
- case 'i': k = ConversionSpecifier::iArg; break;<br>
- case 'n': k = ConversionSpecifier::nArg; break;<br>
- case 'o': k = ConversionSpecifier::oArg; break;<br>
- case 'p': k = ConversionSpecifier::pArg; break;<br>
- case 's': k = ConversionSpecifier::sArg; break;<br>
- case 'u': k = ConversionSpecifier::uArg; break;<br>
- case 'x': k = ConversionSpecifier::xArg; break;<br>
- // POSIX specific.<br>
- case 'C': k = ConversionSpecifier::CArg; break;<br>
- case 'S': k = ConversionSpecifier::SArg; break;<br>
- // Apple extension for os_log<br>
- case 'P':<br>
- k = ConversionSpecifier::PArg;<br>
- break;<br>
- // Objective-C.<br>
- case '@': k = ConversionSpecifier::ObjCObjArg; break;<br>
- // Glibc specific.<br>
- case 'm': k = ConversionSpecifier::PrintErrno; break;<br>
- // FreeBSD kernel specific.<br>
- case 'b':<br>
- if (isFreeBSDKPrintf)<br>
- k = ConversionSpecifier::FreeBSDbArg; // int followed by char *<br>
- break;<br>
- case 'r':<br>
- if (isFreeBSDKPrintf)<br>
- k = ConversionSpecifier::FreeBSDrArg; // int<br>
- break;<br>
- case 'y':<br>
- if (isFreeBSDKPrintf)<br>
- k = ConversionSpecifier::FreeBSDyArg; // int<br>
- break;<br>
- // Apple-specific.<br>
- case 'D':<br>
- if (isFreeBSDKPrintf)<br>
- k = ConversionSpecifier::FreeBSDDArg; // void * followed by char *<br>
- else if (Target.getTriple().isOSDarwin())<br>
- k = ConversionSpecifier::DArg;<br>
- break;<br>
- case 'O':<br>
- if (Target.getTriple().isOSDarwin())<br>
- k = ConversionSpecifier::OArg;<br>
- break;<br>
- case 'U':<br>
- if (Target.getTriple().isOSDarwin())<br>
- k = ConversionSpecifier::UArg;<br>
- break;<br>
- // MS specific.<br>
- case 'Z':<br>
- if (Target.getTriple().isOSMSVCRT())<br>
- k = ConversionSpecifier::ZArg;<br>
- }<br>
-<br>
- // Check to see if we used the Objective-C modifier flags with<br>
- // a conversion specifier other than '@'.<br>
- if (k != ConversionSpecifier::ObjCObjArg &&<br>
- k != ConversionSpecifier::InvalidSpecifier &&<br>
- ObjCModifierFlagsStart) {<br>
- H.HandleObjCFlagsWithNonObjCConversion(ObjCModifierFlagsStart,<br>
- ObjCModifierFlagsEnd + 1,<br>
- conversionPosition);<br>
- return true;<br>
- }<br>
-<br>
- PrintfConversionSpecifier CS(conversionPosition, k);<br>
- FS.setConversionSpecifier(CS);<br>
- if (CS.consumesDataArgument() && !FS.usesPositionalArg())<br>
- FS.setArgIndex(argIndex++);<br>
- // FreeBSD kernel specific.<br>
- if (k == ConversionSpecifier::FreeBSDbArg ||<br>
- k == ConversionSpecifier::FreeBSDDArg)<br>
- argIndex++;<br>
-<br>
- if (k == ConversionSpecifier::InvalidSpecifier) {<br>
- unsigned Len = I - Start;<br>
- if (ParseUTF8InvalidSpecifier(Start, E, Len)) {<br>
- CS.setEndScanList(Start + Len);<br>
- FS.setConversionSpecifier(CS);<br>
- }<br>
- // Assume the conversion takes one argument.<br>
- return !H.HandleInvalidPrintfConversionSpecifier(FS, Start, Len);<br>
- }<br>
- return PrintfSpecifierResult(Start, FS);<br>
-}<br>
-<br>
-bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H,<br>
- const char *I,<br>
- const char *E,<br>
- const LangOptions &LO,<br>
- const TargetInfo &Target,<br>
- bool isFreeBSDKPrintf) {<br>
-<br>
- unsigned argIndex = 0;<br>
-<br>
- // Keep looking for a format specifier until we have exhausted the string.<br>
- while (I != E) {<br>
- const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,<br>
- LO, Target, true,<br>
- isFreeBSDKPrintf);<br>
- // Did a fail-stop error of any kind occur when parsing the specifier?<br>
- // If so, don't do any more processing.<br>
- if (FSR.shouldStop())<br>
- return true;<br>
- // Did we exhaust the string or encounter an error that<br>
- // we can recover from?<br>
- if (!FSR.hasValue())<br>
- continue;<br>
- // We have a format specifier. Pass it to the callback.<br>
- if (!H.HandlePrintfSpecifier(FSR.getValue(), FSR.getStart(),<br>
- I - FSR.getStart()))<br>
- return true;<br>
- }<br>
- assert(I == E && "Format string not exhausted");<br>
- return false;<br>
-}<br>
-<br>
-bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I,<br>
- const char *E,<br>
- const LangOptions &LO,<br>
- const TargetInfo &Target) {<br>
-<br>
- unsigned argIndex = 0;<br>
-<br>
- // Keep looking for a %s format specifier until we have exhausted the string.<br>
- FormatStringHandler H;<br>
- while (I != E) {<br>
- const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex,<br>
- LO, Target, false,<br>
- false);<br>
- // Did a fail-stop error of any kind occur when parsing the specifier?<br>
- // If so, don't do any more processing.<br>
- if (FSR.shouldStop())<br>
- return false;<br>
- // Did we exhaust the string or encounter an error that<br>
- // we can recover from?<br>
- if (!FSR.hasValue())<br>
- continue;<br>
- const analyze_printf::PrintfSpecifier &FS = FSR.getValue();<br>
- // Return true if this a %s format specifier.<br>
- if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg)<br>
- return true;<br>
- }<br>
- return false;<br>
-}<br>
-<br>
-//===----------------------------------------------------------------------===//<br>
-// Methods on PrintfSpecifier.<br>
-//===----------------------------------------------------------------------===//<br>
-<br>
-ArgType PrintfSpecifier::getArgType(ASTContext &Ctx,<br>
- bool IsObjCLiteral) const {<br>
- const PrintfConversionSpecifier &CS = getConversionSpecifier();<br>
-<br>
- if (!CS.consumesDataArgument())<br>
- return ArgType::Invalid();<br>
-<br>
- if (CS.getKind() == ConversionSpecifier::cArg)<br>
- switch (LM.getKind()) {<br>
- case LengthModifier::None:<br>
- return Ctx.IntTy;<br>
- case LengthModifier::AsLong:<br>
- case LengthModifier::AsWide:<br>
- return ArgType(ArgType::WIntTy, "wint_t");<br>
- case LengthModifier::AsShort:<br>
- if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())<br>
- return Ctx.IntTy;<br>
- LLVM_FALLTHROUGH;<br>
- default:<br>
- return ArgType::Invalid();<br>
- }<br>
-<br>
- if (CS.isIntArg())<br>
- switch (LM.getKind()) {<br>
- case LengthModifier::AsLongDouble:<br>
- // GNU extension.<br>
- return Ctx.LongLongTy;<br>
- case LengthModifier::None:<br>
- return Ctx.IntTy;<br>
- case LengthModifier::AsInt32:<br>
- return ArgType(Ctx.IntTy, "__int32");<br>
- case LengthModifier::AsChar: return ArgType::AnyCharTy;<br>
- case LengthModifier::AsShort: return Ctx.ShortTy;<br>
- case LengthModifier::AsLong: return Ctx.LongTy;<br>
- case LengthModifier::AsLongLong:<br>
- case LengthModifier::AsQuad:<br>
- return Ctx.LongLongTy;<br>
- case LengthModifier::AsInt64:<br>
- return ArgType(Ctx.LongLongTy, "__int64");<br>
- case LengthModifier::AsIntMax:<br>
- return ArgType(Ctx.getIntMaxType(), "intmax_t");<br>
- case LengthModifier::AsSizeT:<br>
- return ArgType::makeSizeT(ArgType(Ctx.getSignedSizeType(), "ssize_t"));<br>
- case LengthModifier::AsInt3264:<br>
- return Ctx.getTargetInfo().getTriple().isArch64Bit()<br>
- ? ArgType(Ctx.LongLongTy, "__int64")<br>
- : ArgType(Ctx.IntTy, "__int32");<br>
- case LengthModifier::AsPtrDiff:<br>
- return ArgType::makePtrdiffT(<br>
- ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));<br>
- case LengthModifier::AsAllocate:<br>
- case LengthModifier::AsMAllocate:<br>
- case LengthModifier::AsWide:<br>
- return ArgType::Invalid();<br>
- }<br>
-<br>
- if (CS.isUIntArg())<br>
- switch (LM.getKind()) {<br>
- case LengthModifier::AsLongDouble:<br>
- // GNU extension.<br>
- return Ctx.UnsignedLongLongTy;<br>
- case LengthModifier::None:<br>
- return Ctx.UnsignedIntTy;<br>
- case LengthModifier::AsInt32:<br>
- return ArgType(Ctx.UnsignedIntTy, "unsigned __int32");<br>
- case LengthModifier::AsChar: return Ctx.UnsignedCharTy;<br>
- case LengthModifier::AsShort: return Ctx.UnsignedShortTy;<br>
- case LengthModifier::AsLong: return Ctx.UnsignedLongTy;<br>
- case LengthModifier::AsLongLong:<br>
- case LengthModifier::AsQuad:<br>
- return Ctx.UnsignedLongLongTy;<br>
- case LengthModifier::AsInt64:<br>
- return ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64");<br>
- case LengthModifier::AsIntMax:<br>
- return ArgType(Ctx.getUIntMaxType(), "uintmax_t");<br>
- case LengthModifier::AsSizeT:<br>
- return ArgType::makeSizeT(ArgType(Ctx.getSizeType(), "size_t"));<br>
- case LengthModifier::AsInt3264:<br>
- return Ctx.getTargetInfo().getTriple().isArch64Bit()<br>
- ? ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64")<br>
- : ArgType(Ctx.UnsignedIntTy, "unsigned __int32");<br>
- case LengthModifier::AsPtrDiff:<br>
- return ArgType::makePtrdiffT(<br>
- ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));<br>
- case LengthModifier::AsAllocate:<br>
- case LengthModifier::AsMAllocate:<br>
- case LengthModifier::AsWide:<br>
- return ArgType::Invalid();<br>
- }<br>
-<br>
- if (CS.isDoubleArg()) {<br>
- if (LM.getKind() == LengthModifier::AsLongDouble)<br>
- return Ctx.LongDoubleTy;<br>
- return Ctx.DoubleTy;<br>
- }<br>
-<br>
- if (CS.getKind() == ConversionSpecifier::nArg) {<br>
- switch (LM.getKind()) {<br>
- case LengthModifier::None:<br>
- return ArgType::PtrTo(Ctx.IntTy);<br>
- case LengthModifier::AsChar:<br>
- return ArgType::PtrTo(Ctx.SignedCharTy);<br>
- case LengthModifier::AsShort:<br>
- return ArgType::PtrTo(Ctx.ShortTy);<br>
- case LengthModifier::AsLong:<br>
- return ArgType::PtrTo(Ctx.LongTy);<br>
- case LengthModifier::AsLongLong:<br>
- case LengthModifier::AsQuad:<br>
- return ArgType::PtrTo(Ctx.LongLongTy);<br>
- case LengthModifier::AsIntMax:<br>
- return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));<br>
- case LengthModifier::AsSizeT:<br>
- return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));<br>
- case LengthModifier::AsPtrDiff:<br>
- return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));<br>
- case LengthModifier::AsLongDouble:<br>
- return ArgType(); // FIXME: Is this a known extension?<br>
- case LengthModifier::AsAllocate:<br>
- case LengthModifier::AsMAllocate:<br>
- case LengthModifier::AsInt32:<br>
- case LengthModifier::AsInt3264:<br>
- case LengthModifier::AsInt64:<br>
- case LengthModifier::AsWide:<br>
- return ArgType::Invalid();<br>
- }<br>
- }<br>
-<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::sArg:<br>
- if (LM.getKind() == LengthModifier::AsWideChar) {<br>
- if (IsObjCLiteral)<br>
- return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),<br>
- "const unichar *");<br>
- return ArgType(ArgType::WCStrTy, "wchar_t *");<br>
- }<br>
- if (LM.getKind() == LengthModifier::AsWide)<br>
- return ArgType(ArgType::WCStrTy, "wchar_t *");<br>
- return ArgType::CStrTy;<br>
- case ConversionSpecifier::SArg:<br>
- if (IsObjCLiteral)<br>
- return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()),<br>
- "const unichar *");<br>
- if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&<br>
- LM.getKind() == LengthModifier::AsShort)<br>
- return ArgType::CStrTy;<br>
- return ArgType(ArgType::WCStrTy, "wchar_t *");<br>
- case ConversionSpecifier::CArg:<br>
- if (IsObjCLiteral)<br>
- return ArgType(Ctx.UnsignedShortTy, "unichar");<br>
- if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() &&<br>
- LM.getKind() == LengthModifier::AsShort)<br>
- return Ctx.IntTy;<br>
- return ArgType(Ctx.WideCharTy, "wchar_t");<br>
- case ConversionSpecifier::pArg:<br>
- case ConversionSpecifier::PArg:<br>
- return ArgType::CPointerTy;<br>
- case ConversionSpecifier::ObjCObjArg:<br>
- return ArgType::ObjCPointerTy;<br>
- default:<br>
- break;<br>
- }<br>
-<br>
- // FIXME: Handle other cases.<br>
- return ArgType();<br>
-}<br>
-<br>
-bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt,<br>
- ASTContext &Ctx, bool IsObjCLiteral) {<br>
- // %n is different from other conversion specifiers; don't try to fix it.<br>
- if (CS.getKind() == ConversionSpecifier::nArg)<br>
- return false;<br>
-<br>
- // Handle Objective-C objects first. Note that while the '%@' specifier will<br>
- // not warn for structure pointer or void pointer arguments (because that's<br>
- // how CoreFoundation objects are implemented), we only show a fixit for '%@'<br>
- // if we know it's an object (block, id, class, or __attribute__((NSObject))).<br>
- if (QT->isObjCRetainableType()) {<br>
- if (!IsObjCLiteral)<br>
- return false;<br>
-<br>
- CS.setKind(ConversionSpecifier::ObjCObjArg);<br>
-<br>
- // Disable irrelevant flags<br>
- HasThousandsGrouping = false;<br>
- HasPlusPrefix = false;<br>
- HasSpacePrefix = false;<br>
- HasAlternativeForm = false;<br>
- HasLeadingZeroes = false;<br>
- Precision.setHowSpecified(OptionalAmount::NotSpecified);<br>
- LM.setKind(LengthModifier::None);<br>
-<br>
- return true;<br>
- }<br>
-<br>
- // Handle strings next (char *, wchar_t *)<br>
- if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) {<br>
- CS.setKind(ConversionSpecifier::sArg);<br>
-<br>
- // Disable irrelevant flags<br>
- HasAlternativeForm = 0;<br>
- HasLeadingZeroes = 0;<br>
-<br>
- // Set the long length modifier for wide characters<br>
- if (QT->getPointeeType()->isWideCharType())<br>
- LM.setKind(LengthModifier::AsWideChar);<br>
- else<br>
- LM.setKind(LengthModifier::None);<br>
-<br>
- return true;<br>
- }<br>
-<br>
- // If it's an enum, get its underlying type.<br>
- if (const EnumType *ETy = QT->getAs<EnumType>())<br>
- QT = ETy->getDecl()->getIntegerType();<br>
-<br>
- // We can only work with builtin types.<br>
- const BuiltinType *BT = QT->getAs<BuiltinType>();<br>
- if (!BT)<br>
- return false;<br>
-<br>
- // Set length modifier<br>
- switch (BT->getKind()) {<br>
- case BuiltinType::Bool:<br>
- case BuiltinType::WChar_U:<br>
- case BuiltinType::WChar_S:<br>
- case BuiltinType::Char8: // FIXME: Treat like 'char'?<br>
- case BuiltinType::Char16:<br>
- case BuiltinType::Char32:<br>
- case BuiltinType::UInt128:<br>
- case BuiltinType::Int128:<br>
- case BuiltinType::Half:<br>
- case BuiltinType::Float16:<br>
- case BuiltinType::Float128:<br>
- case BuiltinType::ShortAccum:<br>
- case BuiltinType::Accum:<br>
- case BuiltinType::LongAccum:<br>
- case BuiltinType::UShortAccum:<br>
- case BuiltinType::UAccum:<br>
- case BuiltinType::ULongAccum:<br>
- case BuiltinType::ShortFract:<br>
- case BuiltinType::Fract:<br>
- case BuiltinType::LongFract:<br>
- case BuiltinType::UShortFract:<br>
- case BuiltinType::UFract:<br>
- case BuiltinType::ULongFract:<br>
- case BuiltinType::SatShortAccum:<br>
- case BuiltinType::SatAccum:<br>
- case BuiltinType::SatLongAccum:<br>
- case BuiltinType::SatUShortAccum:<br>
- case BuiltinType::SatUAccum:<br>
- case BuiltinType::SatULongAccum:<br>
- case BuiltinType::SatShortFract:<br>
- case BuiltinType::SatFract:<br>
- case BuiltinType::SatLongFract:<br>
- case BuiltinType::SatUShortFract:<br>
- case BuiltinType::SatUFract:<br>
- case BuiltinType::SatULongFract:<br>
- // Various types which are non-trivial to correct.<br>
- return false;<br>
-<br>
-#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \<br>
- case BuiltinType::Id:<br>
-#include "clang/Basic/OpenCLImageTypes.def"<br>
-#define SIGNED_TYPE(Id, SingletonId)<br>
-#define UNSIGNED_TYPE(Id, SingletonId)<br>
-#define FLOATING_TYPE(Id, SingletonId)<br>
-#define BUILTIN_TYPE(Id, SingletonId) \<br>
- case BuiltinType::Id:<br>
-#include "clang/AST/BuiltinTypes.def"<br>
- // Misc other stuff which doesn't make sense here.<br>
- return false;<br>
-<br>
- case BuiltinType::UInt:<br>
- case BuiltinType::Int:<br>
- case BuiltinType::Float:<br>
- case BuiltinType::Double:<br>
- LM.setKind(LengthModifier::None);<br>
- break;<br>
-<br>
- case BuiltinType::Char_U:<br>
- case BuiltinType::UChar:<br>
- case BuiltinType::Char_S:<br>
- case BuiltinType::SChar:<br>
- LM.setKind(LengthModifier::AsChar);<br>
- break;<br>
-<br>
- case BuiltinType::Short:<br>
- case BuiltinType::UShort:<br>
- LM.setKind(LengthModifier::AsShort);<br>
- break;<br>
-<br>
- case BuiltinType::Long:<br>
- case BuiltinType::ULong:<br>
- LM.setKind(LengthModifier::AsLong);<br>
- break;<br>
-<br>
- case BuiltinType::LongLong:<br>
- case BuiltinType::ULongLong:<br>
- LM.setKind(LengthModifier::AsLongLong);<br>
- break;<br>
-<br>
- case BuiltinType::LongDouble:<br>
- LM.setKind(LengthModifier::AsLongDouble);<br>
- break;<br>
- }<br>
-<br>
- // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.<br>
- if (isa<TypedefType>(QT) && (LangOpt.C99 || LangOpt.CPlusPlus11))<br>
- namedTypeToLengthModifier(QT, LM);<br>
-<br>
- // If fixing the length modifier was enough, we might be done.<br>
- if (hasValidLengthModifier(Ctx.getTargetInfo())) {<br>
- // If we're going to offer a fix anyway, make sure the sign matches.<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::uArg:<br>
- case ConversionSpecifier::UArg:<br>
- if (QT->isSignedIntegerType())<br>
- CS.setKind(clang::analyze_format_string::ConversionSpecifier::dArg);<br>
- break;<br>
- case ConversionSpecifier::dArg:<br>
- case ConversionSpecifier::DArg:<br>
- case ConversionSpecifier::iArg:<br>
- if (QT->isUnsignedIntegerType() && !HasPlusPrefix)<br>
- CS.setKind(clang::analyze_format_string::ConversionSpecifier::uArg);<br>
- break;<br>
- default:<br>
- // Other specifiers do not have signed/unsigned variants.<br>
- break;<br>
- }<br>
-<br>
- const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral);<br>
- if (ATR.isValid() && ATR.matchesType(Ctx, QT))<br>
- return true;<br>
- }<br>
-<br>
- // Set conversion specifier and disable any flags which do not apply to it.<br>
- // Let typedefs to char fall through to int, as %c is silly for uint8_t.<br>
- if (!isa<TypedefType>(QT) && QT->isCharType()) {<br>
- CS.setKind(ConversionSpecifier::cArg);<br>
- LM.setKind(LengthModifier::None);<br>
- Precision.setHowSpecified(OptionalAmount::NotSpecified);<br>
- HasAlternativeForm = 0;<br>
- HasLeadingZeroes = 0;<br>
- HasPlusPrefix = 0;<br>
- }<br>
- // Test for Floating type first as LongDouble can pass isUnsignedIntegerType<br>
- else if (QT->isRealFloatingType()) {<br>
- CS.setKind(ConversionSpecifier::fArg);<br>
- }<br>
- else if (QT->isSignedIntegerType()) {<br>
- CS.setKind(ConversionSpecifier::dArg);<br>
- HasAlternativeForm = 0;<br>
- }<br>
- else if (QT->isUnsignedIntegerType()) {<br>
- CS.setKind(ConversionSpecifier::uArg);<br>
- HasAlternativeForm = 0;<br>
- HasPlusPrefix = 0;<br>
- } else {<br>
- llvm_unreachable("Unexpected type");<br>
- }<br>
-<br>
- return true;<br>
-}<br>
-<br>
-void PrintfSpecifier::toString(raw_ostream &os) const {<br>
- // Whilst some features have no defined order, we are using the order<br>
- // appearing in the C99 standard (ISO/IEC 9899:1999 (E) 7.19.6.1)<br>
- os << "%";<br>
-<br>
- // Positional args<br>
- if (usesPositionalArg()) {<br>
- os << getPositionalArgIndex() << "$";<br>
- }<br>
-<br>
- // Conversion flags<br>
- if (IsLeftJustified) os << "-";<br>
- if (HasPlusPrefix) os << "+";<br>
- if (HasSpacePrefix) os << " ";<br>
- if (HasAlternativeForm) os << "#";<br>
- if (HasLeadingZeroes) os << "0";<br>
-<br>
- // Minimum field width<br>
- FieldWidth.toString(os);<br>
- // Precision<br>
- Precision.toString(os);<br>
- // Length modifier<br>
- os << LM.toString();<br>
- // Conversion specifier<br>
- os << CS.toString();<br>
-}<br>
-<br>
-bool PrintfSpecifier::hasValidPlusPrefix() const {<br>
- if (!HasPlusPrefix)<br>
- return true;<br>
-<br>
- // The plus prefix only makes sense for signed conversions<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::dArg:<br>
- case ConversionSpecifier::DArg:<br>
- case ConversionSpecifier::iArg:<br>
- case ConversionSpecifier::fArg:<br>
- case ConversionSpecifier::FArg:<br>
- case ConversionSpecifier::eArg:<br>
- case ConversionSpecifier::EArg:<br>
- case ConversionSpecifier::gArg:<br>
- case ConversionSpecifier::GArg:<br>
- case ConversionSpecifier::aArg:<br>
- case ConversionSpecifier::AArg:<br>
- case ConversionSpecifier::FreeBSDrArg:<br>
- case ConversionSpecifier::FreeBSDyArg:<br>
- return true;<br>
-<br>
- default:<br>
- return false;<br>
- }<br>
-}<br>
-<br>
-bool PrintfSpecifier::hasValidAlternativeForm() const {<br>
- if (!HasAlternativeForm)<br>
- return true;<br>
-<br>
- // Alternate form flag only valid with the oxXaAeEfFgG conversions<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::oArg:<br>
- case ConversionSpecifier::OArg:<br>
- case ConversionSpecifier::xArg:<br>
- case ConversionSpecifier::XArg:<br>
- case ConversionSpecifier::aArg:<br>
- case ConversionSpecifier::AArg:<br>
- case ConversionSpecifier::eArg:<br>
- case ConversionSpecifier::EArg:<br>
- case ConversionSpecifier::fArg:<br>
- case ConversionSpecifier::FArg:<br>
- case ConversionSpecifier::gArg:<br>
- case ConversionSpecifier::GArg:<br>
- case ConversionSpecifier::FreeBSDrArg:<br>
- case ConversionSpecifier::FreeBSDyArg:<br>
- return true;<br>
-<br>
- default:<br>
- return false;<br>
- }<br>
-}<br>
-<br>
-bool PrintfSpecifier::hasValidLeadingZeros() const {<br>
- if (!HasLeadingZeroes)<br>
- return true;<br>
-<br>
- // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::dArg:<br>
- case ConversionSpecifier::DArg:<br>
- case ConversionSpecifier::iArg:<br>
- case ConversionSpecifier::oArg:<br>
- case ConversionSpecifier::OArg:<br>
- case ConversionSpecifier::uArg:<br>
- case ConversionSpecifier::UArg:<br>
- case ConversionSpecifier::xArg:<br>
- case ConversionSpecifier::XArg:<br>
- case ConversionSpecifier::aArg:<br>
- case ConversionSpecifier::AArg:<br>
- case ConversionSpecifier::eArg:<br>
- case ConversionSpecifier::EArg:<br>
- case ConversionSpecifier::fArg:<br>
- case ConversionSpecifier::FArg:<br>
- case ConversionSpecifier::gArg:<br>
- case ConversionSpecifier::GArg:<br>
- case ConversionSpecifier::FreeBSDrArg:<br>
- case ConversionSpecifier::FreeBSDyArg:<br>
- return true;<br>
-<br>
- default:<br>
- return false;<br>
- }<br>
-}<br>
-<br>
-bool PrintfSpecifier::hasValidSpacePrefix() const {<br>
- if (!HasSpacePrefix)<br>
- return true;<br>
-<br>
- // The space prefix only makes sense for signed conversions<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::dArg:<br>
- case ConversionSpecifier::DArg:<br>
- case ConversionSpecifier::iArg:<br>
- case ConversionSpecifier::fArg:<br>
- case ConversionSpecifier::FArg:<br>
- case ConversionSpecifier::eArg:<br>
- case ConversionSpecifier::EArg:<br>
- case ConversionSpecifier::gArg:<br>
- case ConversionSpecifier::GArg:<br>
- case ConversionSpecifier::aArg:<br>
- case ConversionSpecifier::AArg:<br>
- case ConversionSpecifier::FreeBSDrArg:<br>
- case ConversionSpecifier::FreeBSDyArg:<br>
- return true;<br>
-<br>
- default:<br>
- return false;<br>
- }<br>
-}<br>
-<br>
-bool PrintfSpecifier::hasValidLeftJustified() const {<br>
- if (!IsLeftJustified)<br>
- return true;<br>
-<br>
- // The left justified flag is valid for all conversions except n<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::nArg:<br>
- return false;<br>
-<br>
- default:<br>
- return true;<br>
- }<br>
-}<br>
-<br>
-bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const {<br>
- if (!HasThousandsGrouping)<br>
- return true;<br>
-<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::dArg:<br>
- case ConversionSpecifier::DArg:<br>
- case ConversionSpecifier::iArg:<br>
- case ConversionSpecifier::uArg:<br>
- case ConversionSpecifier::UArg:<br>
- case ConversionSpecifier::fArg:<br>
- case ConversionSpecifier::FArg:<br>
- case ConversionSpecifier::gArg:<br>
- case ConversionSpecifier::GArg:<br>
- return true;<br>
- default:<br>
- return false;<br>
- }<br>
-}<br>
-<br>
-bool PrintfSpecifier::hasValidPrecision() const {<br>
- if (Precision.getHowSpecified() == OptionalAmount::NotSpecified)<br>
- return true;<br>
-<br>
- // Precision is only valid with the diouxXaAeEfFgGsP conversions<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::dArg:<br>
- case ConversionSpecifier::DArg:<br>
- case ConversionSpecifier::iArg:<br>
- case ConversionSpecifier::oArg:<br>
- case ConversionSpecifier::OArg:<br>
- case ConversionSpecifier::uArg:<br>
- case ConversionSpecifier::UArg:<br>
- case ConversionSpecifier::xArg:<br>
- case ConversionSpecifier::XArg:<br>
- case ConversionSpecifier::aArg:<br>
- case ConversionSpecifier::AArg:<br>
- case ConversionSpecifier::eArg:<br>
- case ConversionSpecifier::EArg:<br>
- case ConversionSpecifier::fArg:<br>
- case ConversionSpecifier::FArg:<br>
- case ConversionSpecifier::gArg:<br>
- case ConversionSpecifier::GArg:<br>
- case ConversionSpecifier::sArg:<br>
- case ConversionSpecifier::FreeBSDrArg:<br>
- case ConversionSpecifier::FreeBSDyArg:<br>
- case ConversionSpecifier::PArg:<br>
- return true;<br>
-<br>
- default:<br>
- return false;<br>
- }<br>
-}<br>
-bool PrintfSpecifier::hasValidFieldWidth() const {<br>
- if (FieldWidth.getHowSpecified() == OptionalAmount::NotSpecified)<br>
- return true;<br>
-<br>
- // The field width is valid for all conversions except n<br>
- switch (CS.getKind()) {<br>
- case ConversionSpecifier::nArg:<br>
- return false;<br>
-<br>
- default:<br>
- return true;<br>
- }<br>
-}<br>
<br>
Removed: cfe/trunk/lib/Analysis/ScanfFormatString.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ScanfFormatString.cpp?rev=345970&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ScanfFormatString.cpp?rev=345970&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Analysis/ScanfFormatString.cpp (original)<br>
+++ cfe/trunk/lib/Analysis/ScanfFormatString.cpp (removed)<br>
@@ -1,563 +0,0 @@<br>
-//= ScanfFormatString.cpp - Analysis of printf format strings --*- C++ -*-===//<br>
-//<br>
-// The LLVM Compiler Infrastructure<br>
-//<br>
-// This file is distributed under the University of Illinois Open Source<br>
-// License. See LICENSE.TXT for details.<br>
-//<br>
-//===----------------------------------------------------------------------===//<br>
-//<br>
-// Handling of format string in scanf and friends. The structure of format<br>
-// strings for fscanf() are described in C99 7.19.6.2.<br>
-//<br>
-//===----------------------------------------------------------------------===//<br>
-<br>
-#include "clang/Analysis/Analyses/FormatString.h"<br>
-#include "FormatStringParsing.h"<br>
-#include "clang/Basic/TargetInfo.h"<br>
-<br>
-using clang::analyze_format_string::ArgType;<br>
-using clang::analyze_format_string::FormatStringHandler;<br>
-using clang::analyze_format_string::LengthModifier;<br>
-using clang::analyze_format_string::OptionalAmount;<br>
-using clang::analyze_format_string::ConversionSpecifier;<br>
-using clang::analyze_scanf::ScanfConversionSpecifier;<br>
-using clang::analyze_scanf::ScanfSpecifier;<br>
-using clang::UpdateOnReturn;<br>
-using namespace clang;<br>
-<br>
-typedef clang::analyze_format_string::SpecifierResult<ScanfSpecifier><br>
- ScanfSpecifierResult;<br>
-<br>
-static bool ParseScanList(FormatStringHandler &H,<br>
- ScanfConversionSpecifier &CS,<br>
- const char *&Beg, const char *E) {<br>
- const char *I = Beg;<br>
- const char *start = I - 1;<br>
- UpdateOnReturn <const char*> UpdateBeg(Beg, I);<br>
-<br>
- // No more characters?<br>
- if (I == E) {<br>
- H.HandleIncompleteScanList(start, I);<br>
- return true;<br>
- }<br>
-<br>
- // Special case: ']' is the first character.<br>
- if (*I == ']') {<br>
- if (++I == E) {<br>
- H.HandleIncompleteScanList(start, I - 1);<br>
- return true;<br>
- }<br>
- }<br>
-<br>
- // Special case: "^]" are the first characters.<br>
- if (I + 1 != E && I[0] == '^' && I[1] == ']') {<br>
- I += 2;<br>
- if (I == E) {<br>
- H.HandleIncompleteScanList(start, I - 1);<br>
- return true;<br>
- }<br>
- }<br>
-<br>
- // Look for a ']' character which denotes the end of the scan list.<br>
- while (*I != ']') {<br>
- if (++I == E) {<br>
- H.HandleIncompleteScanList(start, I - 1);<br>
- return true;<br>
- }<br>
- }<br>
-<br>
- CS.setEndScanList(I);<br>
- return false;<br>
-}<br>
-<br>
-// FIXME: Much of this is copy-paste from ParsePrintfSpecifier.<br>
-// We can possibly refactor.<br>
-static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H,<br>
- const char *&Beg,<br>
- const char *E,<br>
- unsigned &argIndex,<br>
- const LangOptions &LO,<br>
- const TargetInfo &Target) {<br>
- using namespace clang::analyze_format_string;<br>
- using namespace clang::analyze_scanf;<br>
- const char *I = Beg;<br>
- const char *Start = nullptr;<br>
- UpdateOnReturn <const char*> UpdateBeg(Beg, I);<br>
-<br>
- // Look for a '%' character that indicates the start of a format specifier.<br>
- for ( ; I != E ; ++I) {<br>
- char c = *I;<br>
- if (c == '\0') {<br>
- // Detect spurious null characters, which are likely errors.<br>
- H.HandleNullChar(I);<br>
- return true;<br>
- }<br>
- if (c == '%') {<br>
- Start = I++; // Record the start of the format specifier.<br>
- break;<br>
- }<br>
- }<br>
-<br>
- // No format specifier found?<br>
- if (!Start)<br>
- return false;<br>
-<br>
- if (I == E) {<br>
- // No more characters left?<br>
- H.HandleIncompleteSpecifier(Start, E - Start);<br>
- return true;<br>
- }<br>
-<br>
- ScanfSpecifier FS;<br>
- if (ParseArgPosition(H, FS, Start, I, E))<br>
- return true;<br>
-<br>
- if (I == E) {<br>
- // No more characters left?<br>
- H.HandleIncompleteSpecifier(Start, E - Start);<br>
- return true;<br>
- }<br>
-<br>
- // Look for '*' flag if it is present.<br>
- if (*I == '*') {<br>
- FS.setSuppressAssignment(I);<br>
- if (++I == E) {<br>
- H.HandleIncompleteSpecifier(Start, E - Start);<br>
- return true;<br>
- }<br>
- }<br>
-<br>
- // Look for the field width (if any). Unlike printf, this is either<br>
- // a fixed integer or isn't present.<br>
- const OptionalAmount &Amt = clang::analyze_format_string::ParseAmount(I, E);<br>
- if (Amt.getHowSpecified() != OptionalAmount::NotSpecified) {<br>
- assert(Amt.getHowSpecified() == OptionalAmount::Constant);<br>
- FS.setFieldWidth(Amt);<br>
-<br>
- if (I == E) {<br>
- // No more characters left?<br>
- H.HandleIncompleteSpecifier(Start, E - Start);<br>
- return true;<br>
- }<br>
- }<br>
-<br>
- // Look for the length modifier.<br>
- if (ParseLengthModifier(FS, I, E, LO, /*scanf=*/true) && I == E) {<br>
- // No more characters left?<br>
- H.HandleIncompleteSpecifier(Start, E - Start);<br>
- return true;<br>
- }<br>
-<br>
- // Detect spurious null characters, which are likely errors.<br>
- if (*I == '\0') {<br>
- H.HandleNullChar(I);<br>
- return true;<br>
- }<br>
-<br>
- // Finally, look for the conversion specifier.<br>
- const char *conversionPosition = I++;<br>
- ScanfConversionSpecifier::Kind k = ScanfConversionSpecifier::InvalidSpecifier;<br>
- switch (*conversionPosition) {<br>
- default:<br>
- break;<br>
- case '%': k = ConversionSpecifier::PercentArg; break;<br>
- case 'A': k = ConversionSpecifier::AArg; break;<br>
- case 'E': k = ConversionSpecifier::EArg; break;<br>
- case 'F': k = ConversionSpecifier::FArg; break;<br>
- case 'G': k = ConversionSpecifier::GArg; break;<br>
- case 'X': k = ConversionSpecifier::XArg; break;<br>
- case 'a': k = ConversionSpecifier::aArg; break;<br>
- case 'd': k = ConversionSpecifier::dArg; break;<br>
- case 'e': k = ConversionSpecifier::eArg; break;<br>
- case 'f': k = ConversionSpecifier::fArg; break;<br>
- case 'g': k = ConversionSpecifier::gArg; break;<br>
- case 'i': k = ConversionSpecifier::iArg; break;<br>
- case 'n': k = ConversionSpecifier::nArg; break;<br>
- case 'c': k = ConversionSpecifier::cArg; break;<br>
- case 'C': k = ConversionSpecifier::CArg; break;<br>
- case 'S': k = ConversionSpecifier::SArg; break;<br>
- case '[': k = ConversionSpecifier::ScanListArg; break;<br>
- case 'u': k = ConversionSpecifier::uArg; break;<br>
- case 'x': k = ConversionSpecifier::xArg; break;<br>
- case 'o': k = ConversionSpecifier::oArg; break;<br>
- case 's': k = ConversionSpecifier::sArg; break;<br>
- case 'p': k = ConversionSpecifier::pArg; break;<br>
- // Apple extensions<br>
- // Apple-specific<br>
- case 'D':<br>
- if (Target.getTriple().isOSDarwin())<br>
- k = ConversionSpecifier::DArg;<br>
- break;<br>
- case 'O':<br>
- if (Target.getTriple().isOSDarwin())<br>
- k = ConversionSpecifier::OArg;<br>
- break;<br>
- case 'U':<br>
- if (Target.getTriple().isOSDarwin())<br>
- k = ConversionSpecifier::UArg;<br>
- break;<br>
- }<br>
- ScanfConversionSpecifier CS(conversionPosition, k);<br>
- if (k == ScanfConversionSpecifier::ScanListArg) {<br>
- if (ParseScanList(H, CS, I, E))<br>
- return true;<br>
- }<br>
- FS.setConversionSpecifier(CS);<br>
- if (CS.consumesDataArgument() && !FS.getSuppressAssignment()<br>
- && !FS.usesPositionalArg())<br>
- FS.setArgIndex(argIndex++);<br>
-<br>
- // FIXME: '%' and '*' doesn't make sense. Issue a warning.<br>
- // FIXME: 'ConsumedSoFar' and '*' doesn't make sense.<br>
-<br>
- if (k == ScanfConversionSpecifier::InvalidSpecifier) {<br>
- unsigned Len = I - Beg;<br>
- if (ParseUTF8InvalidSpecifier(Beg, E, Len)) {<br>
- CS.setEndScanList(Beg + Len);<br>
- FS.setConversionSpecifier(CS);<br>
- }<br>
- // Assume the conversion takes one argument.<br>
- return !H.HandleInvalidScanfConversionSpecifier(FS, Beg, Len);<br>
- }<br>
- return ScanfSpecifierResult(Start, FS);<br>
-}<br>
-<br>
-ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const {<br>
- const ScanfConversionSpecifier &CS = getConversionSpecifier();<br>
-<br>
- if (!CS.consumesDataArgument())<br>
- return ArgType::Invalid();<br>
-<br>
- switch(CS.getKind()) {<br>
- // Signed int.<br>
- case ConversionSpecifier::dArg:<br>
- case ConversionSpecifier::DArg:<br>
- case ConversionSpecifier::iArg:<br>
- switch (LM.getKind()) {<br>
- case LengthModifier::None:<br>
- return ArgType::PtrTo(Ctx.IntTy);<br>
- case LengthModifier::AsChar:<br>
- return ArgType::PtrTo(ArgType::AnyCharTy);<br>
- case LengthModifier::AsShort:<br>
- return ArgType::PtrTo(Ctx.ShortTy);<br>
- case LengthModifier::AsLong:<br>
- return ArgType::PtrTo(Ctx.LongTy);<br>
- case LengthModifier::AsLongLong:<br>
- case LengthModifier::AsQuad:<br>
- return ArgType::PtrTo(Ctx.LongLongTy);<br>
- case LengthModifier::AsInt64:<br>
- return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));<br>
- case LengthModifier::AsIntMax:<br>
- return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));<br>
- case LengthModifier::AsSizeT:<br>
- return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));<br>
- case LengthModifier::AsPtrDiff:<br>
- return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));<br>
- case LengthModifier::AsLongDouble:<br>
- // GNU extension.<br>
- return ArgType::PtrTo(Ctx.LongLongTy);<br>
- case LengthModifier::AsAllocate:<br>
- case LengthModifier::AsMAllocate:<br>
- case LengthModifier::AsInt32:<br>
- case LengthModifier::AsInt3264:<br>
- case LengthModifier::AsWide:<br>
- return ArgType::Invalid();<br>
- }<br>
-<br>
- // Unsigned int.<br>
- case ConversionSpecifier::oArg:<br>
- case ConversionSpecifier::OArg:<br>
- case ConversionSpecifier::uArg:<br>
- case ConversionSpecifier::UArg:<br>
- case ConversionSpecifier::xArg:<br>
- case ConversionSpecifier::XArg:<br>
- switch (LM.getKind()) {<br>
- case LengthModifier::None:<br>
- return ArgType::PtrTo(Ctx.UnsignedIntTy);<br>
- case LengthModifier::AsChar:<br>
- return ArgType::PtrTo(Ctx.UnsignedCharTy);<br>
- case LengthModifier::AsShort:<br>
- return ArgType::PtrTo(Ctx.UnsignedShortTy);<br>
- case LengthModifier::AsLong:<br>
- return ArgType::PtrTo(Ctx.UnsignedLongTy);<br>
- case LengthModifier::AsLongLong:<br>
- case LengthModifier::AsQuad:<br>
- return ArgType::PtrTo(Ctx.UnsignedLongLongTy);<br>
- case LengthModifier::AsInt64:<br>
- return ArgType::PtrTo(ArgType(Ctx.UnsignedLongLongTy, "unsigned __int64"));<br>
- case LengthModifier::AsIntMax:<br>
- return ArgType::PtrTo(ArgType(Ctx.getUIntMaxType(), "uintmax_t"));<br>
- case LengthModifier::AsSizeT:<br>
- return ArgType::PtrTo(ArgType(Ctx.getSizeType(), "size_t"));<br>
- case LengthModifier::AsPtrDiff:<br>
- return ArgType::PtrTo(<br>
- ArgType(Ctx.getUnsignedPointerDiffType(), "unsigned ptrdiff_t"));<br>
- case LengthModifier::AsLongDouble:<br>
- // GNU extension.<br>
- return ArgType::PtrTo(Ctx.UnsignedLongLongTy);<br>
- case LengthModifier::AsAllocate:<br>
- case LengthModifier::AsMAllocate:<br>
- case LengthModifier::AsInt32:<br>
- case LengthModifier::AsInt3264:<br>
- case LengthModifier::AsWide:<br>
- return ArgType::Invalid();<br>
- }<br>
-<br>
- // Float.<br>
- case ConversionSpecifier::aArg:<br>
- case ConversionSpecifier::AArg:<br>
- case ConversionSpecifier::eArg:<br>
- case ConversionSpecifier::EArg:<br>
- case ConversionSpecifier::fArg:<br>
- case ConversionSpecifier::FArg:<br>
- case ConversionSpecifier::gArg:<br>
- case ConversionSpecifier::GArg:<br>
- switch (LM.getKind()) {<br>
- case LengthModifier::None:<br>
- return ArgType::PtrTo(Ctx.FloatTy);<br>
- case LengthModifier::AsLong:<br>
- return ArgType::PtrTo(Ctx.DoubleTy);<br>
- case LengthModifier::AsLongDouble:<br>
- return ArgType::PtrTo(Ctx.LongDoubleTy);<br>
- default:<br>
- return ArgType::Invalid();<br>
- }<br>
-<br>
- // Char, string and scanlist.<br>
- case ConversionSpecifier::cArg:<br>
- case ConversionSpecifier::sArg:<br>
- case ConversionSpecifier::ScanListArg:<br>
- switch (LM.getKind()) {<br>
- case LengthModifier::None:<br>
- return ArgType::PtrTo(ArgType::AnyCharTy);<br>
- case LengthModifier::AsLong:<br>
- case LengthModifier::AsWide:<br>
- return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));<br>
- case LengthModifier::AsAllocate:<br>
- case LengthModifier::AsMAllocate:<br>
- return ArgType::PtrTo(ArgType::CStrTy);<br>
- case LengthModifier::AsShort:<br>
- if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())<br>
- return ArgType::PtrTo(ArgType::AnyCharTy);<br>
- LLVM_FALLTHROUGH;<br>
- default:<br>
- return ArgType::Invalid();<br>
- }<br>
- case ConversionSpecifier::CArg:<br>
- case ConversionSpecifier::SArg:<br>
- // FIXME: Mac OS X specific?<br>
- switch (LM.getKind()) {<br>
- case LengthModifier::None:<br>
- case LengthModifier::AsWide:<br>
- return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t"));<br>
- case LengthModifier::AsAllocate:<br>
- case LengthModifier::AsMAllocate:<br>
- return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *"));<br>
- case LengthModifier::AsShort:<br>
- if (Ctx.getTargetInfo().getTriple().isOSMSVCRT())<br>
- return ArgType::PtrTo(ArgType::AnyCharTy);<br>
- LLVM_FALLTHROUGH;<br>
- default:<br>
- return ArgType::Invalid();<br>
- }<br>
-<br>
- // Pointer.<br>
- case ConversionSpecifier::pArg:<br>
- return ArgType::PtrTo(ArgType::CPointerTy);<br>
-<br>
- // Write-back.<br>
- case ConversionSpecifier::nArg:<br>
- switch (LM.getKind()) {<br>
- case LengthModifier::None:<br>
- return ArgType::PtrTo(Ctx.IntTy);<br>
- case LengthModifier::AsChar:<br>
- return ArgType::PtrTo(Ctx.SignedCharTy);<br>
- case LengthModifier::AsShort:<br>
- return ArgType::PtrTo(Ctx.ShortTy);<br>
- case LengthModifier::AsLong:<br>
- return ArgType::PtrTo(Ctx.LongTy);<br>
- case LengthModifier::AsLongLong:<br>
- case LengthModifier::AsQuad:<br>
- return ArgType::PtrTo(Ctx.LongLongTy);<br>
- case LengthModifier::AsInt64:<br>
- return ArgType::PtrTo(ArgType(Ctx.LongLongTy, "__int64"));<br>
- case LengthModifier::AsIntMax:<br>
- return ArgType::PtrTo(ArgType(Ctx.getIntMaxType(), "intmax_t"));<br>
- case LengthModifier::AsSizeT:<br>
- return ArgType::PtrTo(ArgType(Ctx.getSignedSizeType(), "ssize_t"));<br>
- case LengthModifier::AsPtrDiff:<br>
- return ArgType::PtrTo(ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"));<br>
- case LengthModifier::AsLongDouble:<br>
- return ArgType(); // FIXME: Is this a known extension?<br>
- case LengthModifier::AsAllocate:<br>
- case LengthModifier::AsMAllocate:<br>
- case LengthModifier::AsInt32:<br>
- case LengthModifier::AsInt3264:<br>
- case LengthModifier::AsWide:<br>
- return ArgType::Invalid();<br>
- }<br>
-<br>
- default:<br>
- break;<br>
- }<br>
-<br>
- return ArgType();<br>
-}<br>
-<br>
-bool ScanfSpecifier::fixType(QualType QT, QualType RawQT,<br>
- const LangOptions &LangOpt,<br>
- ASTContext &Ctx) {<br>
-<br>
- // %n is different from other conversion specifiers; don't try to fix it.<br>
- if (CS.getKind() == ConversionSpecifier::nArg)<br>
- return false;<br>
-<br>
- if (!QT->isPointerType())<br>
- return false;<br>
-<br>
- QualType PT = QT->getPointeeType();<br>
-<br>
- // If it's an enum, get its underlying type.<br>
- if (const EnumType *ETy = PT->getAs<EnumType>()) {<br>
- // Don't try to fix incomplete enums.<br>
- if (!ETy->getDecl()->isComplete())<br>
- return false;<br>
- PT = ETy->getDecl()->getIntegerType();<br>
- }<br>
-<br>
- const BuiltinType *BT = PT->getAs<BuiltinType>();<br>
- if (!BT)<br>
- return false;<br>
-<br>
- // Pointer to a character.<br>
- if (PT->isAnyCharacterType()) {<br>
- CS.setKind(ConversionSpecifier::sArg);<br>
- if (PT->isWideCharType())<br>
- LM.setKind(LengthModifier::AsWideChar);<br>
- else<br>
- LM.setKind(LengthModifier::None);<br>
-<br>
- // If we know the target array length, we can use it as a field width.<br>
- if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT)) {<br>
- if (CAT->getSizeModifier() == ArrayType::Normal)<br>
- FieldWidth = OptionalAmount(OptionalAmount::Constant,<br>
- CAT->getSize().getZExtValue() - 1,<br>
- "", 0, false);<br>
-<br>
- }<br>
- return true;<br>
- }<br>
-<br>
- // Figure out the length modifier.<br>
- switch (BT->getKind()) {<br>
- // no modifier<br>
- case BuiltinType::UInt:<br>
- case BuiltinType::Int:<br>
- case BuiltinType::Float:<br>
- LM.setKind(LengthModifier::None);<br>
- break;<br>
-<br>
- // hh<br>
- case BuiltinType::Char_U:<br>
- case BuiltinType::UChar:<br>
- case BuiltinType::Char_S:<br>
- case BuiltinType::SChar:<br>
- LM.setKind(LengthModifier::AsChar);<br>
- break;<br>
-<br>
- // h<br>
- case BuiltinType::Short:<br>
- case BuiltinType::UShort:<br>
- LM.setKind(LengthModifier::AsShort);<br>
- break;<br>
-<br>
- // l<br>
- case BuiltinType::Long:<br>
- case BuiltinType::ULong:<br>
- case BuiltinType::Double:<br>
- LM.setKind(LengthModifier::AsLong);<br>
- break;<br>
-<br>
- // ll<br>
- case BuiltinType::LongLong:<br>
- case BuiltinType::ULongLong:<br>
- LM.setKind(LengthModifier::AsLongLong);<br>
- break;<br>
-<br>
- // L<br>
- case BuiltinType::LongDouble:<br>
- LM.setKind(LengthModifier::AsLongDouble);<br>
- break;<br>
-<br>
- // Don't know.<br>
- default:<br>
- return false;<br>
- }<br>
-<br>
- // Handle size_t, ptrdiff_t, etc. that have dedicated length modifiers in C99.<br>
- if (isa<TypedefType>(PT) && (LangOpt.C99 || LangOpt.CPlusPlus11))<br>
- namedTypeToLengthModifier(PT, LM);<br>
-<br>
- // If fixing the length modifier was enough, we are done.<br>
- if (hasValidLengthModifier(Ctx.getTargetInfo())) {<br>
- const analyze_scanf::ArgType &AT = getArgType(Ctx);<br>
- if (AT.isValid() && AT.matchesType(Ctx, QT))<br>
- return true;<br>
- }<br>
-<br>
- // Figure out the conversion specifier.<br>
- if (PT->isRealFloatingType())<br>
- CS.setKind(ConversionSpecifier::fArg);<br>
- else if (PT->isSignedIntegerType())<br>
- CS.setKind(ConversionSpecifier::dArg);<br>
- else if (PT->isUnsignedIntegerType())<br>
- CS.setKind(ConversionSpecifier::uArg);<br>
- else<br>
- llvm_unreachable("Unexpected type");<br>
-<br>
- return true;<br>
-}<br>
-<br>
-void ScanfSpecifier::toString(raw_ostream &os) const {<br>
- os << "%";<br>
-<br>
- if (usesPositionalArg())<br>
- os << getPositionalArgIndex() << "$";<br>
- if (SuppressAssignment)<br>
- os << "*";<br>
-<br>
- FieldWidth.toString(os);<br>
- os << LM.toString();<br>
- os << CS.toString();<br>
-}<br>
-<br>
-bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H,<br>
- const char *I,<br>
- const char *E,<br>
- const LangOptions &LO,<br>
- const TargetInfo &Target) {<br>
-<br>
- unsigned argIndex = 0;<br>
-<br>
- // Keep looking for a format specifier until we have exhausted the string.<br>
- while (I != E) {<br>
- const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex,<br>
- LO, Target);<br>
- // Did a fail-stop error of any kind occur when parsing the specifier?<br>
- // If so, don't do any more processing.<br>
- if (FSR.shouldStop())<br>
- return true;<br>
- // Did we exhaust the string or encounter an error that<br>
- // we can recover from?<br>
- if (!FSR.hasValue())<br>
- continue;<br>
- // We have a format specifier. Pass it to the callback.<br>
- if (!H.HandleScanfSpecifier(FSR.getValue(), FSR.getStart(),<br>
- I - FSR.getStart())) {<br>
- return true;<br>
- }<br>
- }<br>
- assert(I == E && "Format string not exhausted");<br>
- return false;<br>
-}<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGBuiltin.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBuiltin.cpp?rev=345971&r1=345970&r2=345971&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBuiltin.cpp?rev=345971&r1=345970&r2=345971&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGBuiltin.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGBuiltin.cpp Fri Nov 2 06:14:11 2018<br>
@@ -21,7 +21,7 @@<br>
#include "TargetInfo.h"<br>
#include "clang/AST/ASTContext.h"<br>
#include "clang/AST/Decl.h"<br>
-#include "clang/Analysis/Analyses/OSLog.h"<br>
+#include "clang/AST/OSLog.h"<br>
#include "clang/Basic/TargetBuiltins.h"<br>
#include "clang/Basic/TargetInfo.h"<br>
#include "clang/CodeGen/CGFunctionInfo.h"<br>
@@ -3606,13 +3606,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(<br>
case Builtin::BI__builtin_os_log_format:<br>
return emitBuiltinOSLogFormat(*E);<br>
<br>
- case Builtin::BI__builtin_os_log_format_buffer_size: {<br>
- analyze_os_log::OSLogBufferLayout Layout;<br>
- analyze_os_log::computeOSLogBufferLayout(CGM.getContext(), E, Layout);<br>
- return RValue::get(ConstantInt::get(ConvertType(E->getType()),<br>
- Layout.size().getQuantity()));<br>
- }<br>
-<br>
case Builtin::BI__xray_customevent: {<br>
if (!ShouldXRayInstrumentFunction())<br>
return RValue::getIgnored();<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaChecking.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=345971&r1=345970&r2=345971&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=345971&r1=345970&r2=345971&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaChecking.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaChecking.cpp Fri Nov 2 06:14:11 2018<br>
@@ -27,6 +27,7 @@<br>
#include "clang/AST/ExprCXX.h"<br>
#include "clang/AST/ExprObjC.h"<br>
#include "clang/AST/ExprOpenMP.h"<br>
+#include "clang/AST/FormatString.h"<br>
#include "clang/AST/NSAPI.h"<br>
#include "clang/AST/NonTrivialTypeVisitor.h"<br>
#include "clang/AST/OperationKinds.h"<br>
@@ -35,7 +36,6 @@<br>
#include "clang/AST/Type.h"<br>
#include "clang/AST/TypeLoc.h"<br>
#include "clang/AST/UnresolvedSet.h"<br>
-#include "clang/Analysis/Analyses/FormatString.h"<br>
#include "clang/Basic/AddressSpaces.h"<br>
#include "clang/Basic/CharInfo.h"<br>
#include "clang/Basic/Diagnostic.h"<br>
<br>
Modified: cfe/trunk/test/CodeGen/builtins.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/builtins.c?rev=345971&r1=345970&r2=345971&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/builtins.c?rev=345971&r1=345970&r2=345971&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGen/builtins.c (original)<br>
+++ cfe/trunk/test/CodeGen/builtins.c Fri Nov 2 06:14:11 2018<br>
@@ -729,25 +729,28 @@ void test_builtin_os_log_merge_helper1(v<br>
<br>
// CHECK-LABEL: define void @test_builtin_os_log_errno<br>
void test_builtin_os_log_errno() {<br>
- // CHECK: %[[VLA:.*]] = alloca i8, i64 4, align 16<br>
- // CHECK: call void @__os_log_helper_16_2_1_0_96(i8* %[[VLA]])<br>
+ // CHECK-NOT: @stacksave<br>
+ // CHECK: %[[BUF:.*]] = alloca [4 x i8], align 1<br>
+ // CHECK: %[[DECAY:.*]] = getelementptr inbounds [4 x i8], [4 x i8]* %[[BUF]], i32 0, i32 0<br>
+ // CHECK: call void @__os_log_helper_1_2_1_0_96(i8* %[[DECAY]])<br>
+ // CHECK-NOT: @stackrestore<br>
<br>
char buf[__builtin_os_log_format_buffer_size("%m")];<br>
__builtin_os_log_format(buf, "%m");<br>
}<br>
<br>
-// CHECK-LABEL: define linkonce_odr hidden void @__os_log_helper_16_2_1_0_96<br>
+// CHECK-LABEL: define linkonce_odr hidden void @__os_log_helper_1_2_1_0_96<br>
// CHECK: (i8* %[[BUFFER:.*]])<br>
<br>
// CHECK: %[[BUFFER_ADDR:.*]] = alloca i8*, align 8<br>
// CHECK: store i8* %[[BUFFER]], i8** %[[BUFFER_ADDR]], align 8<br>
// CHECK: %[[BUF:.*]] = load i8*, i8** %[[BUFFER_ADDR]], align 8<br>
// CHECK: %[[SUMMARY:.*]] = getelementptr i8, i8* %[[BUF]], i64 0<br>
-// CHECK: store i8 2, i8* %[[SUMMARY]], align 16<br>
+// CHECK: store i8 2, i8* %[[SUMMARY]], align 1<br>
// CHECK: %[[NUMARGS:.*]] = getelementptr i8, i8* %[[BUF]], i64 1<br>
// CHECK: store i8 1, i8* %[[NUMARGS]], align 1<br>
// CHECK: %[[ARGDESCRIPTOR:.*]] = getelementptr i8, i8* %[[BUF]], i64 2<br>
-// CHECK: store i8 96, i8* %[[ARGDESCRIPTOR]], align 2<br>
+// CHECK: store i8 96, i8* %[[ARGDESCRIPTOR]], align 1<br>
// CHECK: %[[ARGSIZE:.*]] = getelementptr i8, i8* %[[BUF]], i64 3<br>
// CHECK: store i8 0, i8* %[[ARGSIZE]], align 1<br>
// CHECK-NEXT: ret void<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div>