зеркало из https://github.com/microsoft/clang-1.git
Make conversion specifier warning refer to typedef if possible.
For example, the warning for printf("%zu", 42.0); changes from "conversion specifies type 'unsigned long'" to "conversion specifies type 'size_t' (aka 'unsigned long')" git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145697 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
07165b9e3b
Коммит
5fdc1b993d
|
@ -23,6 +23,8 @@
|
|||
|
||||
namespace clang {
|
||||
|
||||
class Sema;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// Common components of both fprintf and fscanf format strings.
|
||||
namespace analyze_format_string {
|
||||
|
@ -448,7 +450,7 @@ public:
|
|||
/// will return null if the format specifier does not have
|
||||
/// a matching data argument or the matching argument matches
|
||||
/// more than one type.
|
||||
ArgTypeResult getArgType(ASTContext &Ctx) const;
|
||||
ArgTypeResult getArgType(Sema &S) const;
|
||||
|
||||
const OptionalFlag &hasThousandsGrouping() const {
|
||||
return HasThousandsGrouping;
|
||||
|
|
|
@ -230,7 +230,8 @@ bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
|
|||
|
||||
case SpecificTy: {
|
||||
argTy = C.getCanonicalType(argTy).getUnqualifiedType();
|
||||
if (T == argTy)
|
||||
QualType U = C.getCanonicalType(T);
|
||||
if (U == argTy)
|
||||
return true;
|
||||
// Check for "compatible types".
|
||||
if (const BuiltinType *BT = argTy->getAs<BuiltinType>())
|
||||
|
@ -239,26 +240,26 @@ bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const {
|
|||
break;
|
||||
case BuiltinType::Char_S:
|
||||
case BuiltinType::SChar:
|
||||
return T == C.UnsignedCharTy;
|
||||
return U == C.UnsignedCharTy;
|
||||
case BuiltinType::Char_U:
|
||||
case BuiltinType::UChar:
|
||||
return T == C.SignedCharTy;
|
||||
return U == C.SignedCharTy;
|
||||
case BuiltinType::Short:
|
||||
return T == C.UnsignedShortTy;
|
||||
return U == C.UnsignedShortTy;
|
||||
case BuiltinType::UShort:
|
||||
return T == C.ShortTy;
|
||||
return U == C.ShortTy;
|
||||
case BuiltinType::Int:
|
||||
return T == C.UnsignedIntTy;
|
||||
return U == C.UnsignedIntTy;
|
||||
case BuiltinType::UInt:
|
||||
return T == C.IntTy;
|
||||
return U == C.IntTy;
|
||||
case BuiltinType::Long:
|
||||
return T == C.UnsignedLongTy;
|
||||
return U == C.UnsignedLongTy;
|
||||
case BuiltinType::ULong:
|
||||
return T == C.LongTy;
|
||||
return U == C.LongTy;
|
||||
case BuiltinType::LongLong:
|
||||
return T == C.UnsignedLongLongTy;
|
||||
return U == C.UnsignedLongLongTy;
|
||||
case BuiltinType::ULongLong:
|
||||
return T == C.LongLongTy;
|
||||
return U == C.LongLongTy;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -485,5 +486,3 @@ bool FormatSpecifier::hasValidLengthModifier() const {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Analysis/Analyses/FormatString.h"
|
||||
#include "clang/Sema/Sema.h"
|
||||
#include "FormatStringParsing.h"
|
||||
|
||||
using clang::analyze_format_string::ArgTypeResult;
|
||||
|
@ -278,8 +279,27 @@ const char *ConversionSpecifier::toString() const {
|
|||
// Methods on PrintfSpecifier.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
|
||||
/// \brief Try to find and return a typedef type named Name whose actual type
|
||||
/// is Underlying. Return Underlying if such a typedef cannot be found.
|
||||
static QualType FindTypedef(Sema &S, const char *Name, QualType Underlying) {
|
||||
ASTContext &Ctx = S.getASTContext();
|
||||
IdentifierInfo &II = Ctx.Idents.get(Name);
|
||||
|
||||
NamedDecl *D = S.LookupSingleName(S.getCurScope(), DeclarationName(&II),
|
||||
SourceLocation(), Sema::LookupOrdinaryName);
|
||||
|
||||
if (TypedefDecl *TD = dyn_cast_or_null<TypedefDecl>(D)) {
|
||||
QualType TypedefType = Ctx.getTypedefType(TD, QualType());
|
||||
if (TD->getUnderlyingType() == Underlying)
|
||||
return TypedefType;
|
||||
}
|
||||
|
||||
return Underlying;
|
||||
}
|
||||
|
||||
ArgTypeResult PrintfSpecifier::getArgType(Sema &S) const {
|
||||
const PrintfConversionSpecifier &CS = getConversionSpecifier();
|
||||
ASTContext &Ctx = S.getASTContext();
|
||||
|
||||
if (!CS.consumesDataArgument())
|
||||
return ArgTypeResult::Invalid();
|
||||
|
@ -301,11 +321,13 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
|
|||
case LengthModifier::AsShort: return Ctx.ShortTy;
|
||||
case LengthModifier::AsLong: return Ctx.LongTy;
|
||||
case LengthModifier::AsLongLong: return Ctx.LongLongTy;
|
||||
case LengthModifier::AsIntMax: return Ctx.getIntMaxType();
|
||||
case LengthModifier::AsIntMax:
|
||||
return FindTypedef(S, "intmax_t", Ctx.getIntMaxType());
|
||||
case LengthModifier::AsSizeT:
|
||||
// FIXME: How to get the corresponding signed version of size_t?
|
||||
return ArgTypeResult();
|
||||
case LengthModifier::AsPtrDiff: return Ctx.getPointerDiffType();
|
||||
case LengthModifier::AsPtrDiff:
|
||||
return FindTypedef(S, "ptrdiff_t", Ctx.getPointerDiffType());
|
||||
}
|
||||
|
||||
if (CS.isUIntArg())
|
||||
|
@ -317,9 +339,10 @@ ArgTypeResult PrintfSpecifier::getArgType(ASTContext &Ctx) const {
|
|||
case LengthModifier::AsShort: return Ctx.UnsignedShortTy;
|
||||
case LengthModifier::AsLong: return Ctx.UnsignedLongTy;
|
||||
case LengthModifier::AsLongLong: return Ctx.UnsignedLongLongTy;
|
||||
case LengthModifier::AsIntMax: return Ctx.getUIntMaxType();
|
||||
case LengthModifier::AsIntMax:
|
||||
return FindTypedef(S, "uintmax_t", Ctx.getUIntMaxType());
|
||||
case LengthModifier::AsSizeT:
|
||||
return Ctx.getSizeType();
|
||||
return FindTypedef(S, "size_t", Ctx.getSizeType());
|
||||
case LengthModifier::AsPtrDiff:
|
||||
// FIXME: How to get the corresponding unsigned
|
||||
// version of ptrdiff_t?
|
||||
|
|
|
@ -2206,7 +2206,7 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
|
|||
// Now type check the data expression that matches the
|
||||
// format specifier.
|
||||
const Expr *Ex = getDataArg(argIndex);
|
||||
const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S.Context);
|
||||
const analyze_printf::ArgTypeResult &ATR = FS.getArgType(S);
|
||||
if (ATR.isValid() && !ATR.matchesType(S.Context, Ex->getType())) {
|
||||
// Check if we didn't match because of an implicit cast from a 'char'
|
||||
// or 'short' to an 'int'. This is done because printf is a varargs
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fsyntax-only -verify %s
|
||||
|
||||
int printf(char const *, ...);
|
||||
|
||||
void test(void) {
|
||||
// size_t, et al. have not been declared yet,
|
||||
// so the warning should refer to the builtin types.
|
||||
printf("%jd", 42.0); // expected-warning {{conversion specifies type 'long long'}}
|
||||
printf("%ju", 42.0); // expected-warning {{conversion specifies type 'unsigned long long'}}
|
||||
printf("%zu", 42.0); // expected-warning {{conversion specifies type 'unsigned long'}}
|
||||
printf("%td", 42.0); // expected-warning {{conversion specifies type 'int'}}
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
typedef __INTMAX_TYPE__ intmax_t;
|
||||
typedef __UINTMAX_TYPE__ uintmax_t;
|
||||
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||
|
||||
printf("%jd", 42.0); // expected-warning {{conversion specifies type 'intmax_t' (aka 'long long')}}
|
||||
printf("%ju", 42.0); // expected-warning {{conversion specifies type 'uintmax_t' (aka 'unsigned long long')}}
|
||||
printf("%zu", 42.0); // expected-warning {{conversion specifies type 'size_t' (aka 'unsigned long')}}
|
||||
printf("%td", 42.0); // expected-warning {{conversion specifies type 'ptrdiff_t' (aka 'int')}}
|
||||
}
|
||||
|
||||
void test2(void) {
|
||||
typedef void *size_t;
|
||||
|
||||
// The typedef for size_t does not match the builtin type,
|
||||
// so the warning should not refer to it.
|
||||
printf("%zu", 42.0); // expected-warning {{conversion specifies type 'unsigned long'}}
|
||||
}
|
Загрузка…
Ссылка в новой задаче