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 return getRangeText(SR: {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` 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
177SourceLocation 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.
185std::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.
198std::optional<StringRef>
199clang::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`.
217std::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.
232SourceLocation 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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of clang/lib/Analysis/FixitUtil.cpp