clang-1/lib/Sema/SemaFixItUtils.cpp

161 строка
5.6 KiB
C++

//===--- 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/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;
}