steveire created this revision. steveire added a reviewer: aaron.ballman. Herald added subscribers: cfe-commits, mgorny. Herald added a project: clang.
The current implementations are concerned with descending through the AST. An addition to the API will be concerned with ascending through the AST in different traversal modes. Keep both in the same class to ensure that they are kept in sync. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D73028 Files: clang/include/clang/AST/ExprTraversal.h clang/lib/AST/CMakeLists.txt clang/lib/AST/Expr.cpp clang/lib/AST/ExprTraversal.cpp
Index: clang/lib/AST/ExprTraversal.cpp =================================================================== --- /dev/null +++ clang/lib/AST/ExprTraversal.cpp @@ -0,0 +1,255 @@ +//===--- ExprTraversal.cpp - Expression AST Node Implementation -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements Expr traversal. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ExprTraversal.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" + + +using namespace clang; + +static Expr *IgnoreImpCastsSingleStep(Expr *E) { + if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) + return ICE->getSubExpr(); + + if (auto *FE = dyn_cast<FullExpr>(E)) + return FE->getSubExpr(); + + return E; +} + +static Expr *IgnoreImpCastsExtraSingleStep(Expr *E) { + // FIXME: Skip MaterializeTemporaryExpr and SubstNonTypeTemplateParmExpr in + // addition to what IgnoreImpCasts() skips to account for the current + // behaviour of IgnoreParenImpCasts(). + Expr *SubE = IgnoreImpCastsSingleStep(E); + if (SubE != E) + return SubE; + + if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) + return MTE->getSubExpr(); + + if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) + return NTTP->getReplacement(); + + return E; +} + +static Expr *IgnoreCastsSingleStep(Expr *E) { + if (auto *CE = dyn_cast<CastExpr>(E)) + return CE->getSubExpr(); + + if (auto *FE = dyn_cast<FullExpr>(E)) + return FE->getSubExpr(); + + if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) + return MTE->getSubExpr(); + + if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) + return NTTP->getReplacement(); + + return E; +} + +static Expr *IgnoreLValueCastsSingleStep(Expr *E) { + // Skip what IgnoreCastsSingleStep skips, except that only + // lvalue-to-rvalue casts are skipped. + if (auto *CE = dyn_cast<CastExpr>(E)) + if (CE->getCastKind() != CK_LValueToRValue) + return E; + + return IgnoreCastsSingleStep(E); +} + +static Expr *IgnoreBaseCastsSingleStep(Expr *E) { + if (auto *CE = dyn_cast<CastExpr>(E)) + if (CE->getCastKind() == CK_DerivedToBase || + CE->getCastKind() == CK_UncheckedDerivedToBase || + CE->getCastKind() == CK_NoOp) + return CE->getSubExpr(); + + return E; +} + +static Expr *IgnoreImplicitSingleStep(Expr *E) { + Expr *SubE = IgnoreImpCastsSingleStep(E); + if (SubE != E) + return SubE; + + if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) + return MTE->getSubExpr(); + + if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E)) + return BTE->getSubExpr(); + + return E; +} + +static Expr *IgnoreImplicitAsWrittenSingleStep(Expr *E) { + if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) + return ICE->getSubExprAsWritten(); + + return IgnoreImplicitSingleStep(E); +} + +static Expr *IgnoreParensOnlySingleStep(Expr *E) { + if (auto *PE = dyn_cast<ParenExpr>(E)) + return PE->getSubExpr(); + return E; +} + +static Expr *IgnoreParensSingleStep(Expr *E) { + if (auto *PE = dyn_cast<ParenExpr>(E)) + return PE->getSubExpr(); + + if (auto *UO = dyn_cast<UnaryOperator>(E)) { + if (UO->getOpcode() == UO_Extension) + return UO->getSubExpr(); + } + + else if (auto *GSE = dyn_cast<GenericSelectionExpr>(E)) { + if (!GSE->isResultDependent()) + return GSE->getResultExpr(); + } + + else if (auto *CE = dyn_cast<ChooseExpr>(E)) { + if (!CE->isConditionDependent()) + return CE->getChosenSubExpr(); + } + + else if (auto *CE = dyn_cast<ConstantExpr>(E)) + return CE->getSubExpr(); + + return E; +} + +static Expr *IgnoreNoopCastsSingleStep(const ASTContext &Ctx, Expr *E) { + if (auto *CE = dyn_cast<CastExpr>(E)) { + // We ignore integer <-> casts that are of the same width, ptr<->ptr and + // ptr<->int casts of the same width. We also ignore all identity casts. + Expr *SubExpr = CE->getSubExpr(); + bool IsIdentityCast = + Ctx.hasSameUnqualifiedType(E->getType(), SubExpr->getType()); + bool IsSameWidthCast = + (E->getType()->isPointerType() || E->getType()->isIntegralType(Ctx)) && + (SubExpr->getType()->isPointerType() || + SubExpr->getType()->isIntegralType(Ctx)) && + (Ctx.getTypeSize(E->getType()) == Ctx.getTypeSize(SubExpr->getType())); + + if (IsIdentityCast || IsSameWidthCast) + return SubExpr; + } + + else if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) + return NTTP->getReplacement(); + + return E; +} + +static Expr *IgnoreExprNodesImpl(Expr *E) { return E; } +template <typename FnTy, typename... FnTys> +static Expr *IgnoreExprNodesImpl(Expr *E, FnTy &&Fn, FnTys &&... Fns) { + return IgnoreExprNodesImpl(Fn(E), std::forward<FnTys>(Fns)...); +} + +/// Given an expression E and functions Fn_1,...,Fn_n : Expr * -> Expr *, +/// Recursively apply each of the functions to E until reaching a fixed point. +/// Note that a null E is valid; in this case nothing is done. +template <typename... FnTys> +static Expr *IgnoreExprNodes(Expr *E, FnTys &&... Fns) { + Expr *LastE = nullptr; + while (E != LastE) { + LastE = E; + E = IgnoreExprNodesImpl(E, std::forward<FnTys>(Fns)...); + } + return E; +} + +Expr *ExprTraversal::DescendIgnoreImpCasts(Expr *E) +{ + return IgnoreExprNodes(E, IgnoreImpCastsSingleStep); +} + +Expr *ExprTraversal::DescendIgnoreCasts(Expr *E) { + return IgnoreExprNodes(E, IgnoreCastsSingleStep); +} + +Expr *ExprTraversal::DescendIgnoreImplicit(Expr *E) { + return IgnoreExprNodes(E, IgnoreImplicitSingleStep); +} + +Expr *ExprTraversal::DescendIgnoreImplicitAsWritten(Expr* E) { + return IgnoreExprNodes(E, IgnoreImplicitAsWrittenSingleStep); +} + +Expr *ExprTraversal::DescendIgnoreParens(Expr* E) { + return IgnoreExprNodes(E, IgnoreParensSingleStep); +} + +Expr *ExprTraversal::DescendIgnoreParenImpCasts(Expr *E) { + return IgnoreExprNodes(E, IgnoreParensSingleStep, + IgnoreImpCastsExtraSingleStep); +} + +Expr *ExprTraversal::DescendIgnoreParenCasts(Expr *E) { + return IgnoreExprNodes(E, IgnoreParensSingleStep, IgnoreCastsSingleStep); +} + +Expr *ExprTraversal::DescendIgnoreConversionOperator(Expr* E) { + if (auto *MCE = dyn_cast<CXXMemberCallExpr>(E)) { + if (MCE->getMethodDecl() && isa<CXXConversionDecl>(MCE->getMethodDecl())) + return MCE->getImplicitObjectArgument(); + } + return E; +} + +Expr *ExprTraversal::DescendIgnoreParenLValueCasts(Expr *E) { + return IgnoreExprNodes(E, IgnoreParensSingleStep, + IgnoreLValueCastsSingleStep); +} + +Expr *ExprTraversal::DescendIgnoreParenBaseCasts(Expr* E) { + return IgnoreExprNodes(E, IgnoreParensSingleStep, + IgnoreBaseCastsSingleStep); +} + +Expr *ExprTraversal::DescendIgnoreParenNoopCasts(const ASTContext &Ctx, Expr *Input) { + return IgnoreExprNodes(Input, IgnoreParensSingleStep, [&Ctx](Expr *E) { + return IgnoreNoopCastsSingleStep(Ctx, E); + }); +} + +Expr *ExprTraversal::DescendIgnoreUnlessSpelledInSource(Expr *E) { + Expr *LastE = nullptr; + while (E != LastE) { + LastE = E; + E = IgnoreExprNodes(E, IgnoreImplicitSingleStep, IgnoreImpCastsSingleStep, IgnoreParensOnlySingleStep); + + auto SR = E->getSourceRange(); + + if (auto *C = dyn_cast<CXXConstructExpr>(E)) { + if (C->getNumArgs() == 1) { + Expr *A = C->getArg(0); + if (A->getSourceRange() == SR || !isa<CXXTemporaryObjectExpr>(C)) + E = A; + } + } + + if (auto *C = dyn_cast<CXXMemberCallExpr>(E)) { + Expr *ExprNode = C->getImplicitObjectArgument()->IgnoreParenImpCasts(); + if (ExprNode->getSourceRange() == SR) + E = ExprNode; + } + } + + return E; +} Index: clang/lib/AST/Expr.cpp =================================================================== --- clang/lib/AST/Expr.cpp +++ clang/lib/AST/Expr.cpp @@ -19,6 +19,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprTraversal.h" #include "clang/AST/Mangle.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" @@ -2816,243 +2817,52 @@ return QualType(); } -static Expr *IgnoreImpCastsSingleStep(Expr *E) { - if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) - return ICE->getSubExpr(); - - if (auto *FE = dyn_cast<FullExpr>(E)) - return FE->getSubExpr(); - - return E; -} - -static Expr *IgnoreImpCastsExtraSingleStep(Expr *E) { - // FIXME: Skip MaterializeTemporaryExpr and SubstNonTypeTemplateParmExpr in - // addition to what IgnoreImpCasts() skips to account for the current - // behaviour of IgnoreParenImpCasts(). - Expr *SubE = IgnoreImpCastsSingleStep(E); - if (SubE != E) - return SubE; - - if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) - return MTE->getSubExpr(); - - if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) - return NTTP->getReplacement(); - - return E; -} - -static Expr *IgnoreCastsSingleStep(Expr *E) { - if (auto *CE = dyn_cast<CastExpr>(E)) - return CE->getSubExpr(); - - if (auto *FE = dyn_cast<FullExpr>(E)) - return FE->getSubExpr(); - - if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) - return MTE->getSubExpr(); - - if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) - return NTTP->getReplacement(); - - return E; -} - -static Expr *IgnoreLValueCastsSingleStep(Expr *E) { - // Skip what IgnoreCastsSingleStep skips, except that only - // lvalue-to-rvalue casts are skipped. - if (auto *CE = dyn_cast<CastExpr>(E)) - if (CE->getCastKind() != CK_LValueToRValue) - return E; - - return IgnoreCastsSingleStep(E); -} - -static Expr *IgnoreBaseCastsSingleStep(Expr *E) { - if (auto *CE = dyn_cast<CastExpr>(E)) - if (CE->getCastKind() == CK_DerivedToBase || - CE->getCastKind() == CK_UncheckedDerivedToBase || - CE->getCastKind() == CK_NoOp) - return CE->getSubExpr(); - - return E; -} - -static Expr *IgnoreImplicitSingleStep(Expr *E) { - Expr *SubE = IgnoreImpCastsSingleStep(E); - if (SubE != E) - return SubE; - - if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) - return MTE->getSubExpr(); - - if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E)) - return BTE->getSubExpr(); - - return E; -} - -static Expr *IgnoreImplicitAsWrittenSingleStep(Expr *E) { - if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) - return ICE->getSubExprAsWritten(); - - return IgnoreImplicitSingleStep(E); -} - -static Expr *IgnoreParensOnlySingleStep(Expr *E) { - if (auto *PE = dyn_cast<ParenExpr>(E)) - return PE->getSubExpr(); - return E; -} - -static Expr *IgnoreParensSingleStep(Expr *E) { - if (auto *PE = dyn_cast<ParenExpr>(E)) - return PE->getSubExpr(); - - if (auto *UO = dyn_cast<UnaryOperator>(E)) { - if (UO->getOpcode() == UO_Extension) - return UO->getSubExpr(); - } - - else if (auto *GSE = dyn_cast<GenericSelectionExpr>(E)) { - if (!GSE->isResultDependent()) - return GSE->getResultExpr(); - } - - else if (auto *CE = dyn_cast<ChooseExpr>(E)) { - if (!CE->isConditionDependent()) - return CE->getChosenSubExpr(); - } - - else if (auto *CE = dyn_cast<ConstantExpr>(E)) - return CE->getSubExpr(); - - return E; -} - -static Expr *IgnoreNoopCastsSingleStep(const ASTContext &Ctx, Expr *E) { - if (auto *CE = dyn_cast<CastExpr>(E)) { - // We ignore integer <-> casts that are of the same width, ptr<->ptr and - // ptr<->int casts of the same width. We also ignore all identity casts. - Expr *SubExpr = CE->getSubExpr(); - bool IsIdentityCast = - Ctx.hasSameUnqualifiedType(E->getType(), SubExpr->getType()); - bool IsSameWidthCast = - (E->getType()->isPointerType() || E->getType()->isIntegralType(Ctx)) && - (SubExpr->getType()->isPointerType() || - SubExpr->getType()->isIntegralType(Ctx)) && - (Ctx.getTypeSize(E->getType()) == Ctx.getTypeSize(SubExpr->getType())); - - if (IsIdentityCast || IsSameWidthCast) - return SubExpr; - } - - else if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) - return NTTP->getReplacement(); - - return E; -} - -static Expr *IgnoreExprNodesImpl(Expr *E) { return E; } -template <typename FnTy, typename... FnTys> -static Expr *IgnoreExprNodesImpl(Expr *E, FnTy &&Fn, FnTys &&... Fns) { - return IgnoreExprNodesImpl(Fn(E), std::forward<FnTys>(Fns)...); -} - -/// Given an expression E and functions Fn_1,...,Fn_n : Expr * -> Expr *, -/// Recursively apply each of the functions to E until reaching a fixed point. -/// Note that a null E is valid; in this case nothing is done. -template <typename... FnTys> -static Expr *IgnoreExprNodes(Expr *E, FnTys &&... Fns) { - Expr *LastE = nullptr; - while (E != LastE) { - LastE = E; - E = IgnoreExprNodesImpl(E, std::forward<FnTys>(Fns)...); - } - return E; -} - Expr *Expr::IgnoreImpCasts() { - return IgnoreExprNodes(this, IgnoreImpCastsSingleStep); + return ExprTraversal::DescendIgnoreImpCasts(this); } Expr *Expr::IgnoreCasts() { - return IgnoreExprNodes(this, IgnoreCastsSingleStep); + return ExprTraversal::DescendIgnoreCasts(this); } Expr *Expr::IgnoreImplicit() { - return IgnoreExprNodes(this, IgnoreImplicitSingleStep); + return ExprTraversal::DescendIgnoreImplicit(this); } Expr *Expr::IgnoreImplicitAsWritten() { - return IgnoreExprNodes(this, IgnoreImplicitAsWrittenSingleStep); + return ExprTraversal::DescendIgnoreImplicitAsWritten(this); } Expr *Expr::IgnoreParens() { - return IgnoreExprNodes(this, IgnoreParensSingleStep); + return ExprTraversal::DescendIgnoreParens(this); } Expr *Expr::IgnoreParenImpCasts() { - return IgnoreExprNodes(this, IgnoreParensSingleStep, - IgnoreImpCastsExtraSingleStep); + return ExprTraversal::DescendIgnoreParenImpCasts(this); } Expr *Expr::IgnoreParenCasts() { - return IgnoreExprNodes(this, IgnoreParensSingleStep, IgnoreCastsSingleStep); + return ExprTraversal::DescendIgnoreParenCasts(this); } Expr *Expr::IgnoreConversionOperator() { - if (auto *MCE = dyn_cast<CXXMemberCallExpr>(this)) { - if (MCE->getMethodDecl() && isa<CXXConversionDecl>(MCE->getMethodDecl())) - return MCE->getImplicitObjectArgument(); - } - return this; + return ExprTraversal::DescendIgnoreConversionOperator(this); } Expr *Expr::IgnoreParenLValueCasts() { - return IgnoreExprNodes(this, IgnoreParensSingleStep, - IgnoreLValueCastsSingleStep); + return ExprTraversal::DescendIgnoreParenLValueCasts(this); } Expr *Expr::ignoreParenBaseCasts() { - return IgnoreExprNodes(this, IgnoreParensSingleStep, - IgnoreBaseCastsSingleStep); + return ExprTraversal::DescendIgnoreParenBaseCasts(this); } Expr *Expr::IgnoreParenNoopCasts(const ASTContext &Ctx) { - return IgnoreExprNodes(this, IgnoreParensSingleStep, [&Ctx](Expr *E) { - return IgnoreNoopCastsSingleStep(Ctx, E); - }); + return ExprTraversal::DescendIgnoreParenNoopCasts(Ctx, this); } Expr *Expr::IgnoreUnlessSpelledInSource() { - Expr *E = this; - - Expr *LastE = nullptr; - while (E != LastE) { - LastE = E; - E = IgnoreExprNodes(E, IgnoreImplicitSingleStep, IgnoreImpCastsSingleStep, - IgnoreParensOnlySingleStep); - - auto SR = E->getSourceRange(); - - if (auto *C = dyn_cast<CXXConstructExpr>(E)) { - if (C->getNumArgs() == 1) { - Expr *A = C->getArg(0); - if (A->getSourceRange() == SR || !isa<CXXTemporaryObjectExpr>(C)) - E = A; - } - } - - if (auto *C = dyn_cast<CXXMemberCallExpr>(E)) { - Expr *ExprNode = C->getImplicitObjectArgument()->IgnoreParenImpCasts(); - if (ExprNode->getSourceRange() == SR) - E = ExprNode; - } - } - - return E; + return ExprTraversal::DescendIgnoreUnlessSpelledInSource(this); } bool Expr::isDefaultArgument() const { Index: clang/lib/AST/CMakeLists.txt =================================================================== --- clang/lib/AST/CMakeLists.txt +++ clang/lib/AST/CMakeLists.txt @@ -50,6 +50,7 @@ ExprConstant.cpp ExprCXX.cpp ExprObjC.cpp + ExprTraversal.cpp ExternalASTMerger.cpp ExternalASTSource.cpp FormatString.cpp Index: clang/include/clang/AST/ExprTraversal.h =================================================================== --- /dev/null +++ clang/include/clang/AST/ExprTraversal.h @@ -0,0 +1,40 @@ +//===--- Expr.h - Classes for representing expressions ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the ExprTraversal class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_EXPR_TRAVERSAL_H +#define LLVM_CLANG_AST_EXPR_TRAVERSAL_H + +namespace clang +{ + +class ASTContext; +class Expr; + +struct ExprTraversal +{ + static Expr *DescendIgnoreImpCasts(Expr *E); + static Expr *DescendIgnoreCasts(Expr *E); + static Expr *DescendIgnoreImplicit(Expr *E); + static Expr *DescendIgnoreImplicitAsWritten(Expr *E); + static Expr *DescendIgnoreParens(Expr *E); + static Expr *DescendIgnoreParenImpCasts(Expr *E); + static Expr *DescendIgnoreParenCasts(Expr *E); + static Expr *DescendIgnoreConversionOperator(Expr *E); + static Expr *DescendIgnoreParenLValueCasts(Expr *E); + static Expr *DescendIgnoreParenBaseCasts(Expr *E); + static Expr *DescendIgnoreParenNoopCasts(const ASTContext &Ctx, Expr *E); + static Expr *DescendIgnoreUnlessSpelledInSource(Expr *E); +}; + +} + +#endif
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits