237 lines · cpp
1//===- FixitUtil.cpp ------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Analysis/Support/FixitUtil.h"10#include "clang/ASTMatchers/ASTMatchers.h"11 12using namespace llvm;13using namespace clang;14using namespace ast_matchers;15 16// Returns the text of the pointee type of `T` from a `VarDecl` of a pointer17// type. The text is obtained through from `TypeLoc`s. Since `TypeLoc` does not18// have source ranges of qualifiers ( The `QualTypeLoc` looks hacky too me19// :( ), `Qualifiers` of the pointee type is returned separately through the20// output parameter `QualifiersToAppend`.21std::optional<std::string>22clang::getPointeeTypeText(const DeclaratorDecl *VD, const SourceManager &SM,23 const LangOptions &LangOpts,24 std::optional<Qualifiers> *QualifiersToAppend) {25 QualType Ty = VD->getType();26 QualType PteTy;27 28 assert(Ty->isPointerType() && !Ty->isFunctionPointerType() &&29 "Expecting a VarDecl of type of pointer to object type");30 PteTy = Ty->getPointeeType();31 32 TypeLoc TyLoc = VD->getTypeSourceInfo()->getTypeLoc().getUnqualifiedLoc();33 TypeLoc PteTyLoc;34 35 // We only deal with the cases that we know `TypeLoc::getNextTypeLoc` returns36 // the `TypeLoc` of the pointee type:37 switch (TyLoc.getTypeLocClass()) {38 case TypeLoc::ConstantArray:39 case TypeLoc::IncompleteArray:40 case TypeLoc::VariableArray:41 case TypeLoc::DependentSizedArray:42 case TypeLoc::Decayed:43 assert(isa<ParmVarDecl>(VD) && "An array type shall not be treated as a "44 "pointer type unless it decays.");45 PteTyLoc = TyLoc.getNextTypeLoc();46 break;47 case TypeLoc::Pointer:48 PteTyLoc = TyLoc.castAs<PointerTypeLoc>().getPointeeLoc();49 break;50 default:51 return std::nullopt;52 }53 if (PteTyLoc.isNull())54 // Sometimes we cannot get a useful `TypeLoc` for the pointee type, e.g.,55 // when the pointer type is `auto`.56 return std::nullopt;57 58 // TODO check59 SourceLocation IdentLoc = VD->getLocation();60 61 if (!(IdentLoc.isValid() && PteTyLoc.getSourceRange().isValid())) {62 // We are expecting these locations to be valid. But in some cases, they are63 // not all valid. It is a Clang bug to me and we are not responsible for64 // fixing it. So we will just give up for now when it happens.65 return std::nullopt;66 }67 68 // Note that TypeLoc.getEndLoc() returns the begin location of the last token:69 SourceLocation PteEndOfTokenLoc =70 Lexer::getLocForEndOfToken(PteTyLoc.getEndLoc(), 0, SM, LangOpts);71 72 if (!PteEndOfTokenLoc.isValid())73 // Sometimes we cannot get the end location of the pointee type, e.g., when74 // there are macros involved.75 return std::nullopt;76 if (!SM.isBeforeInTranslationUnit(PteEndOfTokenLoc, IdentLoc) &&77 PteEndOfTokenLoc != IdentLoc) {78 // We only deal with the cases where the source text of the pointee type79 // appears on the left-hand side of the variable identifier completely,80 // including the following forms:81 // `T ident`,82 // `T ident[]`, where `T` is any type.83 // Examples of excluded cases are `T (*ident)[]` or `T ident[][n]`.84 return std::nullopt;85 }86 if (PteTy.hasQualifiers()) {87 // TypeLoc does not provide source ranges for qualifiers (it says it's88 // intentional but seems fishy to me), so we cannot get the full text89 // `PteTy` via source ranges.90 *QualifiersToAppend = PteTy.getQualifiers();91 }92 return getRangeText({PteTyLoc.getBeginLoc(), PteEndOfTokenLoc}, SM, LangOpts)93 ->str();94}95 96// returns text of pointee to pointee (T*&)97std::optional<std::string>98getPointee2TypeText(const DeclaratorDecl *VD, const SourceManager &SM,99 const LangOptions &LangOpts,100 std::optional<Qualifiers> *QualifiersToAppend) {101 102 QualType Ty = VD->getType();103 assert(Ty->isReferenceType() &&104 "Expecting a VarDecl of reference to pointer type");105 106 Ty = Ty->getPointeeType();107 QualType PteTy;108 109 assert(Ty->isPointerType() && !Ty->isFunctionPointerType() &&110 "Expecting a VarDecl of type of pointer to object type");111 PteTy = Ty->getPointeeType();112 113 TypeLoc TyLoc = VD->getTypeSourceInfo()->getTypeLoc().getUnqualifiedLoc();114 TypeLoc PtrTyLoc;115 TypeLoc PteTyLoc;116 117 // We only deal with the cases that we know `TypeLoc::getNextTypeLoc` returns118 // the `TypeLoc` of the pointee type:119 switch (TyLoc.getTypeLocClass()) {120 case TypeLoc::ConstantArray:121 case TypeLoc::IncompleteArray:122 case TypeLoc::VariableArray:123 case TypeLoc::DependentSizedArray:124 case TypeLoc::LValueReference:125 PtrTyLoc = TyLoc.castAs<ReferenceTypeLoc>().getPointeeLoc();126 if (PtrTyLoc.getTypeLocClass() == TypeLoc::Pointer) {127 PteTyLoc = PtrTyLoc.castAs<PointerTypeLoc>().getPointeeLoc();128 break;129 }130 return std::nullopt;131 break;132 default:133 return std::nullopt;134 }135 if (PteTyLoc.isNull())136 // Sometimes we cannot get a useful `TypeLoc` for the pointee type, e.g.,137 // when the pointer type is `auto`.138 return std::nullopt;139 140 // TODO make sure this works141 SourceLocation IdentLoc = VD->getLocation();142 143 if (!(IdentLoc.isValid() && PteTyLoc.getSourceRange().isValid())) {144 // We are expecting these locations to be valid. But in some cases, they are145 // not all valid. It is a Clang bug to me and we are not responsible for146 // fixing it. So we will just give up for now when it happens.147 return std::nullopt;148 }149 150 // Note that TypeLoc.getEndLoc() returns the begin location of the last token:151 SourceLocation PteEndOfTokenLoc =152 Lexer::getLocForEndOfToken(PteTyLoc.getEndLoc(), 0, SM, LangOpts);153 154 if (!PteEndOfTokenLoc.isValid())155 // Sometimes we cannot get the end location of the pointee type, e.g., when156 // there are macros involved.157 return std::nullopt;158 if (!SM.isBeforeInTranslationUnit(PteEndOfTokenLoc, IdentLoc)) {159 // We only deal with the cases where the source text of the pointee type160 // appears on the left-hand side of the variable identifier completely,161 // including the following forms:162 // `T ident`,163 // `T ident[]`, where `T` is any type.164 // Examples of excluded cases are `T (*ident)[]` or `T ident[][n]`.165 return std::nullopt;166 }167 if (PteTy.hasQualifiers()) {168 // TypeLoc does not provide source ranges for qualifiers (it says it's169 // intentional but seems fishy to me), so we cannot get the full text170 // `PteTy` via source ranges.171 *QualifiersToAppend = PteTy.getQualifiers();172 }173 return getRangeText({PteTyLoc.getBeginLoc(), PteEndOfTokenLoc}, SM, LangOpts)174 ->str();175}176 177SourceLocation clang::getBeginLocOfNestedIdentifier(const DeclaratorDecl *D) {178 if (D->getQualifier()) {179 return D->getQualifierLoc().getBeginLoc();180 }181 return getVarDeclIdentifierLoc(D);182}183 184// Returns the literal text in `SourceRange SR`, if `SR` is a valid range.185std::optional<StringRef> clang::getRangeText(SourceRange SR,186 const SourceManager &SM,187 const LangOptions &LangOpts) {188 bool Invalid = false;189 CharSourceRange CSR = CharSourceRange::getCharRange(SR);190 StringRef Text = Lexer::getSourceText(CSR, SM, LangOpts, &Invalid);191 192 if (!Invalid)193 return Text;194 return std::nullopt;195}196 197// Returns the literal text of the identifier of the given variable declaration.198std::optional<StringRef>199clang::getVarDeclIdentifierText(const DeclaratorDecl *VD,200 const SourceManager &SM,201 const LangOptions &LangOpts) {202 SourceLocation ParmIdentBeginLoc = getBeginLocOfNestedIdentifier(VD);203 SourceLocation ParmIdentEndLoc =204 Lexer::getLocForEndOfToken(getVarDeclIdentifierLoc(VD), 0, SM, LangOpts);205 206 if (VD->getQualifier()) {207 ParmIdentBeginLoc = VD->getQualifierLoc().getBeginLoc();208 }209 210 if (ParmIdentEndLoc.isMacroID() &&211 !Lexer::isAtEndOfMacroExpansion(ParmIdentEndLoc, SM, LangOpts))212 return std::nullopt;213 return getRangeText({ParmIdentBeginLoc, ParmIdentEndLoc}, SM, LangOpts);214}215 216// Return text representation of an `Expr`.217std::optional<StringRef> clang::getExprText(const Expr *E,218 const SourceManager &SM,219 const LangOptions &LangOpts) {220 std::optional<SourceLocation> LastCharLoc = getPastLoc(E, SM, LangOpts);221 222 if (LastCharLoc)223 return Lexer::getSourceText(224 CharSourceRange::getCharRange(E->getBeginLoc(), *LastCharLoc), SM,225 LangOpts);226 227 return std::nullopt;228}229 230// Returns the begin location of the identifier of the given variable231// declaration.232SourceLocation clang::getVarDeclIdentifierLoc(const DeclaratorDecl *VD) {233 // According to the implementation of `VarDecl`, `VD->getLocation()` actually234 // returns the begin location of the identifier of the declaration:235 return VD->getLocation();236}237