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
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 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`.
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` 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
93 std::optional<StringRef> RangeText =
94 getRangeText(SR: {PteTyLoc.getBeginLoc(), PteEndOfTokenLoc}, SM, LangOpts);
95 if (!RangeText)
96 return std::nullopt;
97 return RangeText->str();
98}
99
100// returns text of pointee to pointee (T*&)
101std::optional<std::string>
102getPointee2TypeText(const DeclaratorDecl *VD, const SourceManager &SM,
103 const LangOptions &LangOpts,
104 std::optional<Qualifiers> *QualifiersToAppend) {
105
106 QualType Ty = VD->getType();
107 assert(Ty->isReferenceType() &&
108 "Expecting a VarDecl of reference to pointer type");
109
110 Ty = Ty->getPointeeType();
111 QualType PteTy;
112
113 assert(Ty->isPointerType() && !Ty->isFunctionPointerType() &&
114 "Expecting a VarDecl of type of pointer to object type");
115 PteTy = Ty->getPointeeType();
116
117 TypeLoc TyLoc = VD->getTypeSourceInfo()->getTypeLoc().getUnqualifiedLoc();
118 TypeLoc PtrTyLoc;
119 TypeLoc PteTyLoc;
120
121 // We only deal with the cases that we know `TypeLoc::getNextTypeLoc` returns
122 // the `TypeLoc` of the pointee type:
123 switch (TyLoc.getTypeLocClass()) {
124 case TypeLoc::ConstantArray:
125 case TypeLoc::IncompleteArray:
126 case TypeLoc::VariableArray:
127 case TypeLoc::DependentSizedArray:
128 case TypeLoc::LValueReference:
129 PtrTyLoc = TyLoc.castAs<ReferenceTypeLoc>().getPointeeLoc();
130 if (PtrTyLoc.getTypeLocClass() == TypeLoc::Pointer) {
131 PteTyLoc = PtrTyLoc.castAs<PointerTypeLoc>().getPointeeLoc();
132 break;
133 }
134 return std::nullopt;
135 break;
136 default:
137 return std::nullopt;
138 }
139 if (PteTyLoc.isNull())
140 // Sometimes we cannot get a useful `TypeLoc` for the pointee type, e.g.,
141 // when the pointer type is `auto`.
142 return std::nullopt;
143
144 // TODO make sure this works
145 SourceLocation IdentLoc = VD->getLocation();
146
147 if (!(IdentLoc.isValid() && PteTyLoc.getSourceRange().isValid())) {
148 // We are expecting these locations to be valid. But in some cases, they are
149 // not all valid. It is a Clang bug to me and we are not responsible for
150 // fixing it. So we will just give up for now when it happens.
151 return std::nullopt;
152 }
153
154 // Note that TypeLoc.getEndLoc() returns the begin location of the last token:
155 SourceLocation PteEndOfTokenLoc =
156 Lexer::getLocForEndOfToken(Loc: PteTyLoc.getEndLoc(), Offset: 0, SM, LangOpts);
157
158 if (!PteEndOfTokenLoc.isValid())
159 // Sometimes we cannot get the end location of the pointee type, e.g., when
160 // there are macros involved.
161 return std::nullopt;
162 if (!SM.isBeforeInTranslationUnit(LHS: PteEndOfTokenLoc, RHS: IdentLoc)) {
163 // We only deal with the cases where the source text of the pointee type
164 // appears on the left-hand side of the variable identifier completely,
165 // including the following forms:
166 // `T ident`,
167 // `T ident[]`, where `T` is any type.
168 // Examples of excluded cases are `T (*ident)[]` or `T ident[][n]`.
169 return std::nullopt;
170 }
171 if (PteTy.hasQualifiers()) {
172 // TypeLoc does not provide source ranges for qualifiers (it says it's
173 // intentional but seems fishy to me), so we cannot get the full text
174 // `PteTy` via source ranges.
175 *QualifiersToAppend = PteTy.getQualifiers();
176 }
177 return getRangeText(SR: {PteTyLoc.getBeginLoc(), PteEndOfTokenLoc}, SM, LangOpts)
178 ->str();
179}
180
181SourceLocation clang::getBeginLocOfNestedIdentifier(const DeclaratorDecl *D) {
182 if (D->getQualifier()) {
183 return D->getQualifierLoc().getBeginLoc();
184 }
185 return getVarDeclIdentifierLoc(VD: D);
186}
187
188// Returns the literal text in `SourceRange SR`, if `SR` is a valid range.
189std::optional<StringRef> clang::getRangeText(SourceRange SR,
190 const SourceManager &SM,
191 const LangOptions &LangOpts) {
192 bool Invalid = false;
193 CharSourceRange CSR = CharSourceRange::getCharRange(R: SR);
194 StringRef Text = Lexer::getSourceText(Range: CSR, SM, LangOpts, Invalid: &Invalid);
195
196 if (!Invalid)
197 return Text;
198 return std::nullopt;
199}
200
201// Returns the literal text of the identifier of the given variable declaration.
202std::optional<StringRef>
203clang::getVarDeclIdentifierText(const DeclaratorDecl *VD,
204 const SourceManager &SM,
205 const LangOptions &LangOpts) {
206 SourceLocation ParmIdentBeginLoc = getBeginLocOfNestedIdentifier(D: VD);
207 SourceLocation ParmIdentEndLoc =
208 Lexer::getLocForEndOfToken(Loc: getVarDeclIdentifierLoc(VD), Offset: 0, SM, LangOpts);
209
210 if (VD->getQualifier()) {
211 ParmIdentBeginLoc = VD->getQualifierLoc().getBeginLoc();
212 }
213
214 if (ParmIdentEndLoc.isMacroID() &&
215 !Lexer::isAtEndOfMacroExpansion(loc: ParmIdentEndLoc, SM, LangOpts))
216 return std::nullopt;
217 return getRangeText(SR: {ParmIdentBeginLoc, ParmIdentEndLoc}, SM, LangOpts);
218}
219
220// Return text representation of an `Expr`.
221std::optional<StringRef> clang::getExprText(const Expr *E,
222 const SourceManager &SM,
223 const LangOptions &LangOpts) {
224 std::optional<SourceLocation> LastCharLoc = getPastLoc(Node: E, SM, LangOpts);
225
226 if (LastCharLoc)
227 return Lexer::getSourceText(
228 Range: CharSourceRange::getCharRange(B: E->getBeginLoc(), E: *LastCharLoc), SM,
229 LangOpts);
230
231 return std::nullopt;
232}
233
234// Returns the begin location of the identifier of the given variable
235// declaration.
236SourceLocation clang::getVarDeclIdentifierLoc(const DeclaratorDecl *VD) {
237 // According to the implementation of `VarDecl`, `VD->getLocation()` actually
238 // returns the begin location of the identifier of the declaration:
239 return VD->getLocation();
240}
241