xref: /freebsd/contrib/llvm-project/clang/lib/Analysis/FixitUtil.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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>
getPointeeTypeText(const DeclaratorDecl * VD,const SourceManager & SM,const LangOptions & LangOpts,std::optional<Qualifiers> * QualifiersToAppend)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>
getPointee2TypeText(const DeclaratorDecl * VD,const SourceManager & SM,const LangOptions & LangOpts,std::optional<Qualifiers> * QualifiersToAppend)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 
getBeginLocOfNestedIdentifier(const DeclaratorDecl * D)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.
getRangeText(SourceRange SR,const SourceManager & SM,const LangOptions & LangOpts)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>
getVarDeclIdentifierText(const DeclaratorDecl * VD,const SourceManager & SM,const LangOptions & LangOpts)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`.
getExprText(const Expr * E,const SourceManager & SM,const LangOptions & LangOpts)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.
getVarDeclIdentifierLoc(const DeclaratorDecl * VD)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