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(Loc: PteTyLoc.getEndLoc(), Offset: 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(LHS: PteEndOfTokenLoc, RHS: 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(SR: {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(Loc: PteTyLoc.getEndLoc(), Offset: 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(LHS: PteEndOfTokenLoc, RHS: 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(SR: {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(VD: 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(R: SR); |
190 | StringRef Text = Lexer::getSourceText(Range: CSR, SM, LangOpts, Invalid: &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(D: VD); |
203 | SourceLocation ParmIdentEndLoc = |
204 | Lexer::getLocForEndOfToken(Loc: getVarDeclIdentifierLoc(VD), Offset: 0, SM, LangOpts); |
205 | |
206 | if (VD->getQualifier()) { |
207 | ParmIdentBeginLoc = VD->getQualifierLoc().getBeginLoc(); |
208 | } |
209 | |
210 | if (ParmIdentEndLoc.isMacroID() && |
211 | !Lexer::isAtEndOfMacroExpansion(loc: ParmIdentEndLoc, SM, LangOpts)) |
212 | return std::nullopt; |
213 | return getRangeText(SR: {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(Node: E, SM, LangOpts); |
221 | |
222 | if (LastCharLoc) |
223 | return Lexer::getSourceText( |
224 | Range: 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 | |