QualType TypeFinder::LargestType(const Expr* Left, const Expr* Right) { QualType TL = findType(Left); QualType TR = findType(Right); // TODO cleanup QualType Lcanon = TL.getCanonicalType(); QualType Rcanon = TR.getCanonicalType(); assert(Lcanon.isBuiltinType()); assert(Rcanon.isBuiltinType()); const BuiltinType* Lbi = cast<BuiltinType>(Lcanon); const BuiltinType* Rbi = cast<BuiltinType>(Rcanon); if (Lbi->getWidth() > Rbi->getWidth()) { return TL; } return TR; }
// FIXME: add support for derived types. // FIXME: check default character kind. bool Sema::CheckEquivalenceType(QualType ExpectedType, const Expr *E) { auto ObjectType = E->getType(); if(ObjectType->isArrayType()) ObjectType = ObjectType->asArrayType()->getElementType(); if(ExpectedType->isCharacterType()) { if(!ObjectType->isCharacterType()) { Diags.Report(E->getLocation(), diag::err_typecheck_expected_char_expr) << ObjectType << E->getSourceRange(); return true; } } else if(ExpectedType->isBuiltinType()) { if(IsDefaultBuiltinOrDoublePrecisionType(ExpectedType)) { if(!IsDefaultBuiltinOrDoublePrecisionType(ObjectType)) { Diags.Report(E->getLocation(), diag::err_typecheck_expected_default_kind_expr) << ObjectType << E->getSourceRange(); return true; } } else { if(!AreTypesOfSameKind(ExpectedType, ObjectType)) { Diags.Report(E->getLocation(), diag::err_typecheck_expected_expr_of_type) << ExpectedType << ObjectType << E->getSourceRange(); return true; } } } return false; }
bool LiteralAnalyser::calcWidth(QualType TLeft, const Expr* Right, int* availableWidth) { const QualType QT = TLeft.getCanonicalType(); // TODO check if type is already ok?, then skip check? //if (QT == Right->getType().getCanonicalType()) return; if (QT.isBuiltinType()) { const BuiltinType* TL = cast<BuiltinType>(QT); if (!TL->isInteger()) { // TODO floats return false; } // TODO remove const cast Expr* EE = const_cast<Expr*>(Right); QualType Canon = EE->getType().getCanonicalType(); assert(Canon->isBuiltinType()); const BuiltinType* BI = cast<BuiltinType>(Canon); if (TL->getKind() != BI->getKind()) EE->setImpCast(TL->getKind()); if (QT == Type::Bool()) { // NOTE: any integer to bool is ok return false; } *availableWidth = TL->getIntegerWidth(); } else if (QT.isPointerType()) { *availableWidth = 32; // only 32-bit for now // dont ask for pointer, replace with uint32 here. } else { StringBuilder t1name(128); Right->getType().DiagName(t1name); // Q: allow FuncPtr to return 0? (or nil?) StringBuilder t2name(128); TLeft->DiagName(t2name); Diags.Report(Right->getLocation(), diag::err_typecheck_convert_incompatible) << t1name << t2name << 2 << 0 << 0; return false; //QT.dump(); //assert(0 && "todo"); } return true; }
bool LiteralAnalyser::checkRange(QualType TLeft, const Expr* Right, clang::SourceLocation Loc, llvm::APSInt Result) { // TODO refactor with check() const QualType QT = TLeft.getCanonicalType(); int availableWidth = 0; if (QT.isBuiltinType()) { const BuiltinType* TL = cast<BuiltinType>(QT); if (!TL->isInteger()) { // TODO floats return false; } availableWidth = TL->getIntegerWidth(); } else { QT.dump(); assert(0 && "todo"); } const Limit* L = getLimit(availableWidth); assert(Result.isSigned() && "TEMP FOR NOW"); int64_t value = Result.getSExtValue(); bool overflow = false; if (Result.isNegative()) { const int64_t limit = L->minVal; if (value < limit) overflow = true; } else { const int64_t limit = (int64_t)L->maxVal; if (value > limit) overflow = true; } //fprintf(stderr, "VAL=%lld width=%d signed=%d\n", value, availableWidth, Result.isSigned()); if (overflow) { SmallString<20> ss; Result.toString(ss, 10, true); StringBuilder buf1; TLeft->DiagName(buf1); if (Right) { Diags.Report(Right->getLocStart(), diag::err_literal_outofbounds) << buf1 << L->minStr << L->maxStr << ss << Right->getSourceRange(); } else { Diags.Report(Loc, diag::err_literal_outofbounds) << buf1 << L->minStr << L->maxStr << ss; } return false; } return true; }
void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) { const auto *CastExpr = Result.Nodes.getNodeAs<CStyleCastExpr>("cast"); auto ParenRange = CharSourceRange::getTokenRange(CastExpr->getLParenLoc(), CastExpr->getRParenLoc()); // Ignore casts in macros. if (ParenRange.getBegin().isMacroID() || ParenRange.getEnd().isMacroID()) return; // Casting to void is an idiomatic way to mute "unused variable" and similar // warnings. if (CastExpr->getTypeAsWritten()->isVoidType()) return; QualType SourceType = CastExpr->getSubExprAsWritten()->getType().getCanonicalType(); QualType DestType = CastExpr->getTypeAsWritten().getCanonicalType(); if (SourceType == DestType) { diag(CastExpr->getLocStart(), "Redundant cast to the same type.") << FixItHint::CreateRemoval(ParenRange); return; } // The rest of this check is only relevant to C++. if (!Result.Context->getLangOpts().CPlusPlus) return; // Leave type spelling exactly as it was (unlike // getTypeAsWritten().getAsString() which would spell enum types 'enum X'). StringRef DestTypeString = Lexer::getSourceText( CharSourceRange::getTokenRange( CastExpr->getLParenLoc().getLocWithOffset(1), CastExpr->getRParenLoc().getLocWithOffset(-1)), *Result.SourceManager, Result.Context->getLangOpts()); auto diag_builder = diag(CastExpr->getLocStart(), "C-style casts are discouraged. %0"); auto ReplaceWithCast = [&](StringRef CastType) { diag_builder << ("Use " + CastType + ".").str(); const Expr *SubExpr = CastExpr->getSubExprAsWritten()->IgnoreImpCasts(); std::string CastText = (CastType + "<" + DestTypeString + ">").str(); if (!isa<ParenExpr>(SubExpr)) { CastText.push_back('('); diag_builder << FixItHint::CreateInsertion( Lexer::getLocForEndOfToken(SubExpr->getLocEnd(), 0, *Result.SourceManager, Result.Context->getLangOpts()), ")"); } diag_builder << FixItHint::CreateReplacement(ParenRange, CastText); }; // Suggest appropriate C++ cast. See [expr.cast] for cast notation semantics. switch (CastExpr->getCastKind()) { case CK_NoOp: if (needsConstCast(SourceType, DestType) && pointedTypesAreEqual(SourceType, DestType)) { ReplaceWithCast("const_cast"); return; } if (DestType->isReferenceType() && (SourceType.getNonReferenceType() == DestType.getNonReferenceType().withConst() || SourceType.getNonReferenceType() == DestType.getNonReferenceType())) { ReplaceWithCast("const_cast"); return; } // FALLTHROUGH case clang::CK_IntegralCast: // Convert integral and no-op casts between builtin types and enums to // static_cast. A cast from enum to integer may be unnecessary, but it's // still retained. if ((SourceType->isBuiltinType() || SourceType->isEnumeralType()) && (DestType->isBuiltinType() || DestType->isEnumeralType())) { ReplaceWithCast("static_cast"); return; } break; case CK_BitCast: // FIXME: Suggest const_cast<...>(reinterpret_cast<...>(...)) replacement. if (!needsConstCast(SourceType, DestType)) { ReplaceWithCast("reinterpret_cast"); return; } break; default: break; } diag_builder << "Use static_cast/const_cast/reinterpret_cast."; }
bool PrintfSpecifier::fixType(QualType QT) { // Handle strings first (char *, wchar_t *) if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { CS.setKind(ConversionSpecifier::sArg); // Disable irrelevant flags HasAlternativeForm = 0; HasLeadingZeroes = 0; // Set the long length modifier for wide characters if (QT->getPointeeType()->isWideCharType()) LM.setKind(LengthModifier::AsWideChar); return true; } // We can only work with builtin types. if (!QT->isBuiltinType()) return false; // Everything else should be a base type const BuiltinType *BT = QT->getAs<BuiltinType>(); // Set length modifier switch (BT->getKind()) { default: // The rest of the conversions are either optional or for non-builtin types LM.setKind(LengthModifier::None); break; case BuiltinType::WChar: case BuiltinType::Long: case BuiltinType::ULong: LM.setKind(LengthModifier::AsLong); break; case BuiltinType::LongLong: case BuiltinType::ULongLong: LM.setKind(LengthModifier::AsLongLong); break; case BuiltinType::LongDouble: LM.setKind(LengthModifier::AsLongDouble); break; } // Set conversion specifier and disable any flags which do not apply to it. if (QT->isAnyCharacterType()) { CS.setKind(ConversionSpecifier::cArg); Precision.setHowSpecified(OptionalAmount::NotSpecified); HasAlternativeForm = 0; HasLeadingZeroes = 0; HasPlusPrefix = 0; } // Test for Floating type first as LongDouble can pass isUnsignedIntegerType else if (QT->isRealFloatingType()) { CS.setKind(ConversionSpecifier::fArg); } else if (QT->isPointerType()) { CS.setKind(ConversionSpecifier::pArg); Precision.setHowSpecified(OptionalAmount::NotSpecified); HasAlternativeForm = 0; HasLeadingZeroes = 0; HasPlusPrefix = 0; } else if (QT->isSignedIntegerType()) { CS.setKind(ConversionSpecifier::dArg); HasAlternativeForm = 0; } else if (QT->isUnsignedIntegerType()) { CS.setKind(ConversionSpecifier::uArg); HasAlternativeForm = 0; HasPlusPrefix = 0; } else { return false; } return true; }
bool PrintfSpecifier::fixType(QualType QT) { // Handle strings first (char *, wchar_t *) if (QT->isPointerType() && (QT->getPointeeType()->isAnyCharacterType())) { CS.setKind(ConversionSpecifier::sArg); // Disable irrelevant flags HasAlternativeForm = 0; HasLeadingZeroes = 0; // Set the long length modifier for wide characters if (QT->getPointeeType()->isWideCharType()) LM.setKind(LengthModifier::AsWideChar); return true; } // We can only work with builtin types. if (!QT->isBuiltinType()) return false; // Everything else should be a base type const BuiltinType *BT = QT->getAs<BuiltinType>(); // Set length modifier switch (BT->getKind()) { case BuiltinType::Bool: case BuiltinType::WChar_U: case BuiltinType::WChar_S: case BuiltinType::Char16: case BuiltinType::Char32: case BuiltinType::UInt128: case BuiltinType::Int128: // Integral types which are non-trivial to correct. return false; case BuiltinType::Void: case BuiltinType::NullPtr: case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: case BuiltinType::Dependent: case BuiltinType::Overload: case BuiltinType::BoundMember: case BuiltinType::UnknownAny: // Misc other stuff which doesn't make sense here. return false; case BuiltinType::UInt: case BuiltinType::Int: case BuiltinType::Float: case BuiltinType::Double: LM.setKind(LengthModifier::None); break; case BuiltinType::Char_U: case BuiltinType::UChar: case BuiltinType::Char_S: case BuiltinType::SChar: LM.setKind(LengthModifier::AsChar); break; case BuiltinType::Short: case BuiltinType::UShort: LM.setKind(LengthModifier::AsShort); break; case BuiltinType::Long: case BuiltinType::ULong: LM.setKind(LengthModifier::AsLong); break; case BuiltinType::LongLong: case BuiltinType::ULongLong: LM.setKind(LengthModifier::AsLongLong); break; case BuiltinType::LongDouble: LM.setKind(LengthModifier::AsLongDouble); break; } // Set conversion specifier and disable any flags which do not apply to it. // Let typedefs to char fall through to int, as %c is silly for uint8_t. if (isa<TypedefType>(QT) && QT->isAnyCharacterType()) { CS.setKind(ConversionSpecifier::cArg); LM.setKind(LengthModifier::None); Precision.setHowSpecified(OptionalAmount::NotSpecified); HasAlternativeForm = 0; HasLeadingZeroes = 0; HasPlusPrefix = 0; } // Test for Floating type first as LongDouble can pass isUnsignedIntegerType else if (QT->isRealFloatingType()) { CS.setKind(ConversionSpecifier::fArg); } else if (QT->isSignedIntegerType()) { CS.setKind(ConversionSpecifier::dArg); HasAlternativeForm = 0; } else if (QT->isUnsignedIntegerType()) { // Preserve the original formatting, e.g. 'X', 'o'. if (!cast<PrintfConversionSpecifier>(CS).isUIntArg()) CS.setKind(ConversionSpecifier::uArg); HasAlternativeForm = 0; HasPlusPrefix = 0; } else { llvm_unreachable("Unexpected type"); } return true; }
void AvoidCStyleCastsCheck::check(const MatchFinder::MatchResult &Result) { const auto *CastExpr = Result.Nodes.getNodeAs<CStyleCastExpr>("cast"); // Ignore casts in macros. if (CastExpr->getExprLoc().isMacroID()) return; // Casting to void is an idiomatic way to mute "unused variable" and similar // warnings. if (CastExpr->getCastKind() == CK_ToVoid) return; auto isFunction = [](QualType T) { T = T.getCanonicalType().getNonReferenceType(); return T->isFunctionType() || T->isFunctionPointerType() || T->isMemberFunctionPointerType(); }; const QualType DestTypeAsWritten = CastExpr->getTypeAsWritten().getUnqualifiedType(); const QualType SourceTypeAsWritten = CastExpr->getSubExprAsWritten()->getType().getUnqualifiedType(); const QualType SourceType = SourceTypeAsWritten.getCanonicalType(); const QualType DestType = DestTypeAsWritten.getCanonicalType(); auto ReplaceRange = CharSourceRange::getCharRange( CastExpr->getLParenLoc(), CastExpr->getSubExprAsWritten()->getBeginLoc()); bool FnToFnCast = isFunction(SourceTypeAsWritten) && isFunction(DestTypeAsWritten); if (CastExpr->getCastKind() == CK_NoOp && !FnToFnCast) { // Function pointer/reference casts may be needed to resolve ambiguities in // case of overloaded functions, so detection of redundant casts is trickier // in this case. Don't emit "redundant cast" warnings for function // pointer/reference types. if (SourceTypeAsWritten == DestTypeAsWritten) { diag(CastExpr->getBeginLoc(), "redundant cast to the same type") << FixItHint::CreateRemoval(ReplaceRange); return; } } // The rest of this check is only relevant to C++. // We also disable it for Objective-C++. if (!getLangOpts().CPlusPlus || getLangOpts().ObjC1 || getLangOpts().ObjC2) return; // Ignore code inside extern "C" {} blocks. if (!match(expr(hasAncestor(linkageSpecDecl())), *CastExpr, *Result.Context) .empty()) return; // Ignore code in .c files and headers included from them, even if they are // compiled as C++. if (getCurrentMainFile().endswith(".c")) return; SourceManager &SM = *Result.SourceManager; // Ignore code in .c files #included in other files (which shouldn't be done, // but people still do this for test and other purposes). if (SM.getFilename(SM.getSpellingLoc(CastExpr->getBeginLoc())).endswith(".c")) return; // Leave type spelling exactly as it was (unlike // getTypeAsWritten().getAsString() which would spell enum types 'enum X'). StringRef DestTypeString = Lexer::getSourceText(CharSourceRange::getTokenRange( CastExpr->getLParenLoc().getLocWithOffset(1), CastExpr->getRParenLoc().getLocWithOffset(-1)), SM, getLangOpts()); auto Diag = diag(CastExpr->getBeginLoc(), "C-style casts are discouraged; use %0"); auto ReplaceWithCast = [&](std::string CastText) { const Expr *SubExpr = CastExpr->getSubExprAsWritten()->IgnoreImpCasts(); if (!isa<ParenExpr>(SubExpr)) { CastText.push_back('('); Diag << FixItHint::CreateInsertion( Lexer::getLocForEndOfToken(SubExpr->getEndLoc(), 0, SM, getLangOpts()), ")"); } Diag << FixItHint::CreateReplacement(ReplaceRange, CastText); }; auto ReplaceWithNamedCast = [&](StringRef CastType) { Diag << CastType; ReplaceWithCast((CastType + "<" + DestTypeString + ">").str()); }; // Suggest appropriate C++ cast. See [expr.cast] for cast notation semantics. switch (CastExpr->getCastKind()) { case CK_FunctionToPointerDecay: ReplaceWithNamedCast("static_cast"); return; case CK_ConstructorConversion: if (!CastExpr->getTypeAsWritten().hasQualifiers() && DestTypeAsWritten->isRecordType() && !DestTypeAsWritten->isElaboratedTypeSpecifier()) { Diag << "constructor call syntax"; // FIXME: Validate DestTypeString, maybe. ReplaceWithCast(DestTypeString.str()); } else { ReplaceWithNamedCast("static_cast"); } return; case CK_NoOp: if (FnToFnCast) { ReplaceWithNamedCast("static_cast"); return; } if (SourceType == DestType) { Diag << "static_cast (if needed, the cast may be redundant)"; ReplaceWithCast(("static_cast<" + DestTypeString + ">").str()); return; } if (needsConstCast(SourceType, DestType) && pointedUnqualifiedTypesAreEqual(SourceType, DestType)) { ReplaceWithNamedCast("const_cast"); return; } if (DestType->isReferenceType()) { QualType Dest = DestType.getNonReferenceType(); QualType Source = SourceType.getNonReferenceType(); if (Source == Dest.withConst() || SourceType.getNonReferenceType() == DestType.getNonReferenceType()) { ReplaceWithNamedCast("const_cast"); return; } break; } // FALLTHROUGH case clang::CK_IntegralCast: // Convert integral and no-op casts between builtin types and enums to // static_cast. A cast from enum to integer may be unnecessary, but it's // still retained. if ((SourceType->isBuiltinType() || SourceType->isEnumeralType()) && (DestType->isBuiltinType() || DestType->isEnumeralType())) { ReplaceWithNamedCast("static_cast"); return; } break; case CK_BitCast: // FIXME: Suggest const_cast<...>(reinterpret_cast<...>(...)) replacement. if (!needsConstCast(SourceType, DestType)) { if (SourceType->isVoidPointerType()) ReplaceWithNamedCast("static_cast"); else ReplaceWithNamedCast("reinterpret_cast"); return; } break; default: break; } Diag << "static_cast/const_cast/reinterpret_cast"; }