Path: blob/main/contrib/llvm-project/clang/lib/Analysis/FixitUtil.cpp
213766 views
//===- FixitUtil.cpp ------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "clang/Analysis/Support/FixitUtil.h"9#include "clang/ASTMatchers/ASTMatchers.h"1011using namespace llvm;12using namespace clang;13using namespace ast_matchers;1415// Returns the text of the pointee type of `T` from a `VarDecl` of a pointer16// type. The text is obtained through from `TypeLoc`s. Since `TypeLoc` does not17// have source ranges of qualifiers ( The `QualTypeLoc` looks hacky too me18// :( ), `Qualifiers` of the pointee type is returned separately through the19// output parameter `QualifiersToAppend`.20std::optional<std::string>21clang::getPointeeTypeText(const DeclaratorDecl *VD, const SourceManager &SM,22const LangOptions &LangOpts,23std::optional<Qualifiers> *QualifiersToAppend) {24QualType Ty = VD->getType();25QualType PteTy;2627assert(Ty->isPointerType() && !Ty->isFunctionPointerType() &&28"Expecting a VarDecl of type of pointer to object type");29PteTy = Ty->getPointeeType();3031TypeLoc TyLoc = VD->getTypeSourceInfo()->getTypeLoc().getUnqualifiedLoc();32TypeLoc PteTyLoc;3334// We only deal with the cases that we know `TypeLoc::getNextTypeLoc` returns35// the `TypeLoc` of the pointee type:36switch (TyLoc.getTypeLocClass()) {37case TypeLoc::ConstantArray:38case TypeLoc::IncompleteArray:39case TypeLoc::VariableArray:40case TypeLoc::DependentSizedArray:41case TypeLoc::Decayed:42assert(isa<ParmVarDecl>(VD) && "An array type shall not be treated as a "43"pointer type unless it decays.");44PteTyLoc = TyLoc.getNextTypeLoc();45break;46case TypeLoc::Pointer:47PteTyLoc = TyLoc.castAs<PointerTypeLoc>().getPointeeLoc();48break;49default:50return std::nullopt;51}52if (PteTyLoc.isNull())53// Sometimes we cannot get a useful `TypeLoc` for the pointee type, e.g.,54// when the pointer type is `auto`.55return std::nullopt;5657// TODO check58SourceLocation IdentLoc = VD->getLocation();5960if (!(IdentLoc.isValid() && PteTyLoc.getSourceRange().isValid())) {61// We are expecting these locations to be valid. But in some cases, they are62// not all valid. It is a Clang bug to me and we are not responsible for63// fixing it. So we will just give up for now when it happens.64return std::nullopt;65}6667// Note that TypeLoc.getEndLoc() returns the begin location of the last token:68SourceLocation PteEndOfTokenLoc =69Lexer::getLocForEndOfToken(PteTyLoc.getEndLoc(), 0, SM, LangOpts);7071if (!PteEndOfTokenLoc.isValid())72// Sometimes we cannot get the end location of the pointee type, e.g., when73// there are macros involved.74return std::nullopt;75if (!SM.isBeforeInTranslationUnit(PteEndOfTokenLoc, IdentLoc) &&76PteEndOfTokenLoc != IdentLoc) {77// We only deal with the cases where the source text of the pointee type78// appears on the left-hand side of the variable identifier completely,79// including the following forms:80// `T ident`,81// `T ident[]`, where `T` is any type.82// Examples of excluded cases are `T (*ident)[]` or `T ident[][n]`.83return std::nullopt;84}85if (PteTy.hasQualifiers()) {86// TypeLoc does not provide source ranges for qualifiers (it says it's87// intentional but seems fishy to me), so we cannot get the full text88// `PteTy` via source ranges.89*QualifiersToAppend = PteTy.getQualifiers();90}91return getRangeText({PteTyLoc.getBeginLoc(), PteEndOfTokenLoc}, SM, LangOpts)92->str();93}9495// returns text of pointee to pointee (T*&)96std::optional<std::string>97getPointee2TypeText(const DeclaratorDecl *VD, const SourceManager &SM,98const LangOptions &LangOpts,99std::optional<Qualifiers> *QualifiersToAppend) {100101QualType Ty = VD->getType();102assert(Ty->isReferenceType() &&103"Expecting a VarDecl of reference to pointer type");104105Ty = Ty->getPointeeType();106QualType PteTy;107108assert(Ty->isPointerType() && !Ty->isFunctionPointerType() &&109"Expecting a VarDecl of type of pointer to object type");110PteTy = Ty->getPointeeType();111112TypeLoc TyLoc = VD->getTypeSourceInfo()->getTypeLoc().getUnqualifiedLoc();113TypeLoc PtrTyLoc;114TypeLoc PteTyLoc;115116// We only deal with the cases that we know `TypeLoc::getNextTypeLoc` returns117// the `TypeLoc` of the pointee type:118switch (TyLoc.getTypeLocClass()) {119case TypeLoc::ConstantArray:120case TypeLoc::IncompleteArray:121case TypeLoc::VariableArray:122case TypeLoc::DependentSizedArray:123case TypeLoc::LValueReference:124PtrTyLoc = TyLoc.castAs<ReferenceTypeLoc>().getPointeeLoc();125if (PtrTyLoc.getTypeLocClass() == TypeLoc::Pointer) {126PteTyLoc = PtrTyLoc.castAs<PointerTypeLoc>().getPointeeLoc();127break;128}129return std::nullopt;130break;131default:132return std::nullopt;133}134if (PteTyLoc.isNull())135// Sometimes we cannot get a useful `TypeLoc` for the pointee type, e.g.,136// when the pointer type is `auto`.137return std::nullopt;138139// TODO make sure this works140SourceLocation IdentLoc = VD->getLocation();141142if (!(IdentLoc.isValid() && PteTyLoc.getSourceRange().isValid())) {143// We are expecting these locations to be valid. But in some cases, they are144// not all valid. It is a Clang bug to me and we are not responsible for145// fixing it. So we will just give up for now when it happens.146return std::nullopt;147}148149// Note that TypeLoc.getEndLoc() returns the begin location of the last token:150SourceLocation PteEndOfTokenLoc =151Lexer::getLocForEndOfToken(PteTyLoc.getEndLoc(), 0, SM, LangOpts);152153if (!PteEndOfTokenLoc.isValid())154// Sometimes we cannot get the end location of the pointee type, e.g., when155// there are macros involved.156return std::nullopt;157if (!SM.isBeforeInTranslationUnit(PteEndOfTokenLoc, IdentLoc)) {158// We only deal with the cases where the source text of the pointee type159// appears on the left-hand side of the variable identifier completely,160// including the following forms:161// `T ident`,162// `T ident[]`, where `T` is any type.163// Examples of excluded cases are `T (*ident)[]` or `T ident[][n]`.164return std::nullopt;165}166if (PteTy.hasQualifiers()) {167// TypeLoc does not provide source ranges for qualifiers (it says it's168// intentional but seems fishy to me), so we cannot get the full text169// `PteTy` via source ranges.170*QualifiersToAppend = PteTy.getQualifiers();171}172return getRangeText({PteTyLoc.getBeginLoc(), PteEndOfTokenLoc}, SM, LangOpts)173->str();174}175176SourceLocation clang::getBeginLocOfNestedIdentifier(const DeclaratorDecl *D) {177if (D->getQualifier()) {178return D->getQualifierLoc().getBeginLoc();179}180return getVarDeclIdentifierLoc(D);181}182183// Returns the literal text in `SourceRange SR`, if `SR` is a valid range.184std::optional<StringRef> clang::getRangeText(SourceRange SR,185const SourceManager &SM,186const LangOptions &LangOpts) {187bool Invalid = false;188CharSourceRange CSR = CharSourceRange::getCharRange(SR);189StringRef Text = Lexer::getSourceText(CSR, SM, LangOpts, &Invalid);190191if (!Invalid)192return Text;193return std::nullopt;194}195196// Returns the literal text of the identifier of the given variable declaration.197std::optional<StringRef>198clang::getVarDeclIdentifierText(const DeclaratorDecl *VD,199const SourceManager &SM,200const LangOptions &LangOpts) {201SourceLocation ParmIdentBeginLoc = getBeginLocOfNestedIdentifier(VD);202SourceLocation ParmIdentEndLoc =203Lexer::getLocForEndOfToken(getVarDeclIdentifierLoc(VD), 0, SM, LangOpts);204205if (VD->getQualifier()) {206ParmIdentBeginLoc = VD->getQualifierLoc().getBeginLoc();207}208209if (ParmIdentEndLoc.isMacroID() &&210!Lexer::isAtEndOfMacroExpansion(ParmIdentEndLoc, SM, LangOpts))211return std::nullopt;212return getRangeText({ParmIdentBeginLoc, ParmIdentEndLoc}, SM, LangOpts);213}214215// Return text representation of an `Expr`.216std::optional<StringRef> clang::getExprText(const Expr *E,217const SourceManager &SM,218const LangOptions &LangOpts) {219std::optional<SourceLocation> LastCharLoc = getPastLoc(E, SM, LangOpts);220221if (LastCharLoc)222return Lexer::getSourceText(223CharSourceRange::getCharRange(E->getBeginLoc(), *LastCharLoc), SM,224LangOpts);225226return std::nullopt;227}228229// Returns the begin location of the identifier of the given variable230// declaration.231SourceLocation clang::getVarDeclIdentifierLoc(const DeclaratorDecl *VD) {232// According to the implementation of `VarDecl`, `VD->getLocation()` actually233// returns the begin location of the identifier of the declaration:234return VD->getLocation();235}236237238