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