diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaFixItUtils.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaFixItUtils.cpp | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaFixItUtils.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaFixItUtils.cpp new file mode 100644 index 0000000..32b56bc --- /dev/null +++ b/contrib/llvm/tools/clang/lib/Sema/SemaFixItUtils.cpp @@ -0,0 +1,225 @@ +//===--- SemaFixItUtils.cpp - Sema FixIts ---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines helper classes for generation of Sema FixItHints. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaFixItUtils.h" + +using namespace clang; + +bool ConversionFixItGenerator::compareTypesSimple(CanQualType From, + CanQualType To, + Sema &S, + SourceLocation Loc, + ExprValueKind FromVK) { + if (!To.isAtLeastAsQualifiedAs(From)) + return false; + + From = From.getNonReferenceType(); + To = To.getNonReferenceType(); + + // If both are pointer types, work with the pointee types. + if (isa<PointerType>(From) && isa<PointerType>(To)) { + From = S.Context.getCanonicalType( + (cast<PointerType>(From))->getPointeeType()); + To = S.Context.getCanonicalType( + (cast<PointerType>(To))->getPointeeType()); + } + + const CanQualType FromUnq = From.getUnqualifiedType(); + const CanQualType ToUnq = To.getUnqualifiedType(); + + if ((FromUnq == ToUnq || (S.IsDerivedFrom(FromUnq, ToUnq)) ) && + To.isAtLeastAsQualifiedAs(From)) + return true; + return false; +} + +bool ConversionFixItGenerator::tryToFixConversion(const Expr *FullExpr, + const QualType FromTy, + const QualType ToTy, + Sema &S) { + if (!FullExpr) + return false; + + const CanQualType FromQTy = S.Context.getCanonicalType(FromTy); + const CanQualType ToQTy = S.Context.getCanonicalType(ToTy); + const SourceLocation Begin = FullExpr->getSourceRange().getBegin(); + const SourceLocation End = S.PP.getLocForEndOfToken(FullExpr->getSourceRange() + .getEnd()); + + // Strip the implicit casts - those are implied by the compiler, not the + // original source code. + const Expr* Expr = FullExpr->IgnoreImpCasts(); + + bool NeedParen = true; + if (isa<ArraySubscriptExpr>(Expr) || + isa<CallExpr>(Expr) || + isa<DeclRefExpr>(Expr) || + isa<CastExpr>(Expr) || + isa<CXXNewExpr>(Expr) || + isa<CXXConstructExpr>(Expr) || + isa<CXXDeleteExpr>(Expr) || + isa<CXXNoexceptExpr>(Expr) || + isa<CXXPseudoDestructorExpr>(Expr) || + isa<CXXScalarValueInitExpr>(Expr) || + isa<CXXThisExpr>(Expr) || + isa<CXXTypeidExpr>(Expr) || + isa<CXXUnresolvedConstructExpr>(Expr) || + isa<ObjCMessageExpr>(Expr) || + isa<ObjCPropertyRefExpr>(Expr) || + isa<ObjCProtocolExpr>(Expr) || + isa<MemberExpr>(Expr) || + isa<ParenExpr>(FullExpr) || + isa<ParenListExpr>(Expr) || + isa<SizeOfPackExpr>(Expr) || + isa<UnaryOperator>(Expr)) + NeedParen = false; + + // Check if the argument needs to be dereferenced: + // (type * -> type) or (type * -> type &). + if (const PointerType *FromPtrTy = dyn_cast<PointerType>(FromQTy)) { + OverloadFixItKind FixKind = OFIK_Dereference; + + bool CanConvert = CompareTypes( + S.Context.getCanonicalType(FromPtrTy->getPointeeType()), ToQTy, + S, Begin, VK_LValue); + if (CanConvert) { + // Do not suggest dereferencing a Null pointer. + if (Expr->IgnoreParenCasts()-> + isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)) + return false; + + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) { + if (UO->getOpcode() == UO_AddrOf) { + FixKind = OFIK_RemoveTakeAddress; + Hints.push_back(FixItHint::CreateRemoval( + CharSourceRange::getTokenRange(Begin, Begin))); + } + } else if (NeedParen) { + Hints.push_back(FixItHint::CreateInsertion(Begin, "*(")); + Hints.push_back(FixItHint::CreateInsertion(End, ")")); + } else { + Hints.push_back(FixItHint::CreateInsertion(Begin, "*")); + } + + NumConversionsFixed++; + if (NumConversionsFixed == 1) + Kind = FixKind; + return true; + } + } + + // Check if the pointer to the argument needs to be passed: + // (type -> type *) or (type & -> type *). + if (isa<PointerType>(ToQTy)) { + bool CanConvert = false; + OverloadFixItKind FixKind = OFIK_TakeAddress; + + // Only suggest taking address of L-values. + if (!Expr->isLValue() || Expr->getObjectKind() != OK_Ordinary) + return false; + + CanConvert = CompareTypes(S.Context.getPointerType(FromQTy), ToQTy, + S, Begin, VK_RValue); + if (CanConvert) { + + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Expr)) { + if (UO->getOpcode() == UO_Deref) { + FixKind = OFIK_RemoveDereference; + Hints.push_back(FixItHint::CreateRemoval( + CharSourceRange::getTokenRange(Begin, Begin))); + } + } else if (NeedParen) { + Hints.push_back(FixItHint::CreateInsertion(Begin, "&(")); + Hints.push_back(FixItHint::CreateInsertion(End, ")")); + } else { + Hints.push_back(FixItHint::CreateInsertion(Begin, "&")); + } + + NumConversionsFixed++; + if (NumConversionsFixed == 1) + Kind = FixKind; + return true; + } + } + + return false; +} + +static bool isMacroDefined(const Sema &S, SourceLocation Loc, StringRef Name) { + const IdentifierInfo *II = &S.getASTContext().Idents.get(Name); + if (!II->hadMacroDefinition()) return false; + + MacroDirective *Macro = S.PP.getMacroDirectiveHistory(II); + return Macro && Macro->findDirectiveAtLoc(Loc, S.getSourceManager()); +} + +static std::string getScalarZeroExpressionForType( + const Type &T, SourceLocation Loc, const Sema &S) { + assert(T.isScalarType() && "use scalar types only"); + // Suggest "0" for non-enumeration scalar types, unless we can find a + // better initializer. + if (T.isEnumeralType()) + return std::string(); + if ((T.isObjCObjectPointerType() || T.isBlockPointerType()) && + isMacroDefined(S, Loc, "nil")) + return "nil"; + if (T.isRealFloatingType()) + return "0.0"; + if (T.isBooleanType() && + (S.LangOpts.CPlusPlus || isMacroDefined(S, Loc, "false"))) + return "false"; + if (T.isPointerType() || T.isMemberPointerType()) { + if (S.LangOpts.CPlusPlus11) + return "nullptr"; + if (isMacroDefined(S, Loc, "NULL")) + return "NULL"; + } + if (T.isCharType()) + return "'\\0'"; + if (T.isWideCharType()) + return "L'\\0'"; + if (T.isChar16Type()) + return "u'\\0'"; + if (T.isChar32Type()) + return "U'\\0'"; + return "0"; +} + +std::string +Sema::getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const { + if (T->isScalarType()) { + std::string s = getScalarZeroExpressionForType(*T, Loc, *this); + if (!s.empty()) + s = " = " + s; + return s; + } + + const CXXRecordDecl *RD = T->getAsCXXRecordDecl(); + if (!RD || !RD->hasDefinition()) + return std::string(); + if (LangOpts.CPlusPlus11 && !RD->hasUserProvidedDefaultConstructor()) + return "{}"; + if (RD->isAggregate()) + return " = {}"; + return std::string(); +} + +std::string +Sema::getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const { + return getScalarZeroExpressionForType(*T, Loc, *this); +} |