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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/Analysis/Support/FixitUtil.h" 10 #include "clang/ASTMatchers/ASTMatchers.h" 11 12 using namespace llvm; 13 using namespace clang; 14 using namespace ast_matchers; 15 16 // Returns the text of the pointee type of `T` from a `VarDecl` of a pointer 17 // type. The text is obtained through from `TypeLoc`s. Since `TypeLoc` does not 18 // have source ranges of qualifiers ( The `QualTypeLoc` looks hacky too me 19 // :( ), `Qualifiers` of the pointee type is returned separately through the 20 // output parameter `QualifiersToAppend`. 21 std::optional<std::string> 22 clang::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` returns 36 // 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 check 59 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 are 63 // not all valid. It is a Clang bug to me and we are not responsible for 64 // 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., when 74 // 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 type 79 // 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's 88 // intentional but seems fishy to me), so we cannot get the full text 89 // `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*&) 97 std::optional<std::string> 98 getPointee2TypeText(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` returns 118 // 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 works 141 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 are 145 // not all valid. It is a Clang bug to me and we are not responsible for 146 // 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., when 156 // 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 type 160 // 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's 169 // intentional but seems fishy to me), so we cannot get the full text 170 // `PteTy` via source ranges. 171 *QualifiersToAppend = PteTy.getQualifiers(); 172 } 173 return getRangeText({PteTyLoc.getBeginLoc(), PteEndOfTokenLoc}, SM, LangOpts) 174 ->str(); 175 } 176 177 SourceLocation 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. 185 std::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. 198 std::optional<StringRef> 199 clang::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`. 217 std::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 variable 231 // declaration. 232 SourceLocation clang::getVarDeclIdentifierLoc(const DeclaratorDecl *VD) { 233 // According to the implementation of `VarDecl`, `VD->getLocation()` actually 234 // returns the begin location of the identifier of the declaration: 235 return VD->getLocation(); 236 } 237