Bug Summary

File:clang/include/clang/Basic/FileEntry.h
Warning:line 62, column 38
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ObjCMT.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/tools/clang/lib/ARCMigrate -resource-dir /usr/lib/llvm-14/lib/clang/14.0.0 -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/tools/clang/lib/ARCMigrate -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/clang/lib/ARCMigrate -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/clang/include -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/tools/clang/include -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/include -I /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/include -D NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/build-llvm/tools/clang/lib/ARCMigrate -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e=. -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2021-09-04-040900-46481-1 -x c++ /build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/clang/lib/ARCMigrate/ObjCMT.cpp

/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/clang/lib/ARCMigrate/ObjCMT.cpp

1//===--- ObjCMT.cpp - ObjC Migrate Tool -----------------------------------===//
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 "Transforms.h"
10#include "clang/Analysis/RetainSummaryManager.h"
11#include "clang/ARCMigrate/ARCMT.h"
12#include "clang/ARCMigrate/ARCMTActions.h"
13#include "clang/AST/ASTConsumer.h"
14#include "clang/AST/ASTContext.h"
15#include "clang/AST/Attr.h"
16#include "clang/AST/NSAPI.h"
17#include "clang/AST/ParentMap.h"
18#include "clang/AST/RecursiveASTVisitor.h"
19#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
20#include "clang/Basic/FileManager.h"
21#include "clang/Edit/Commit.h"
22#include "clang/Edit/EditedSource.h"
23#include "clang/Edit/EditsReceiver.h"
24#include "clang/Edit/Rewriters.h"
25#include "clang/Frontend/CompilerInstance.h"
26#include "clang/Frontend/MultiplexConsumer.h"
27#include "clang/Lex/PPConditionalDirectiveRecord.h"
28#include "clang/Lex/Preprocessor.h"
29#include "clang/Rewrite/Core/Rewriter.h"
30#include "llvm/ADT/SmallString.h"
31#include "llvm/ADT/StringSet.h"
32#include "llvm/Support/Path.h"
33#include "llvm/Support/SourceMgr.h"
34#include "llvm/Support/YAMLParser.h"
35
36using namespace clang;
37using namespace arcmt;
38using namespace ento;
39
40namespace {
41
42class ObjCMigrateASTConsumer : public ASTConsumer {
43 enum CF_BRIDGING_KIND {
44 CF_BRIDGING_NONE,
45 CF_BRIDGING_ENABLE,
46 CF_BRIDGING_MAY_INCLUDE
47 };
48
49 void migrateDecl(Decl *D);
50 void migrateObjCContainerDecl(ASTContext &Ctx, ObjCContainerDecl *D);
51 void migrateProtocolConformance(ASTContext &Ctx,
52 const ObjCImplementationDecl *ImpDecl);
53 void CacheObjCNSIntegerTypedefed(const TypedefDecl *TypedefDcl);
54 bool migrateNSEnumDecl(ASTContext &Ctx, const EnumDecl *EnumDcl,
55 const TypedefDecl *TypedefDcl);
56 void migrateAllMethodInstaceType(ASTContext &Ctx, ObjCContainerDecl *CDecl);
57 void migrateMethodInstanceType(ASTContext &Ctx, ObjCContainerDecl *CDecl,
58 ObjCMethodDecl *OM);
59 bool migrateProperty(ASTContext &Ctx, ObjCContainerDecl *D, ObjCMethodDecl *OM);
60 void migrateNsReturnsInnerPointer(ASTContext &Ctx, ObjCMethodDecl *OM);
61 void migratePropertyNsReturnsInnerPointer(ASTContext &Ctx, ObjCPropertyDecl *P);
62 void migrateFactoryMethod(ASTContext &Ctx, ObjCContainerDecl *CDecl,
63 ObjCMethodDecl *OM,
64 ObjCInstanceTypeFamily OIT_Family = OIT_None);
65
66 void migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl);
67 void AddCFAnnotations(ASTContext &Ctx,
68 const RetainSummary *RS,
69 const FunctionDecl *FuncDecl, bool ResultAnnotated);
70 void AddCFAnnotations(ASTContext &Ctx,
71 const RetainSummary *RS,
72 const ObjCMethodDecl *MethodDecl, bool ResultAnnotated);
73
74 void AnnotateImplicitBridging(ASTContext &Ctx);
75
76 CF_BRIDGING_KIND migrateAddFunctionAnnotation(ASTContext &Ctx,
77 const FunctionDecl *FuncDecl);
78
79 void migrateARCSafeAnnotation(ASTContext &Ctx, ObjCContainerDecl *CDecl);
80
81 void migrateAddMethodAnnotation(ASTContext &Ctx,
82 const ObjCMethodDecl *MethodDecl);
83
84 void inferDesignatedInitializers(ASTContext &Ctx,
85 const ObjCImplementationDecl *ImplD);
86
87 bool InsertFoundation(ASTContext &Ctx, SourceLocation Loc);
88
89 std::unique_ptr<RetainSummaryManager> Summaries;
90
91public:
92 std::string MigrateDir;
93 unsigned ASTMigrateActions;
94 FileID FileId;
95 const TypedefDecl *NSIntegerTypedefed;
96 const TypedefDecl *NSUIntegerTypedefed;
97 std::unique_ptr<NSAPI> NSAPIObj;
98 std::unique_ptr<edit::EditedSource> Editor;
99 FileRemapper &Remapper;
100 FileManager &FileMgr;
101 const PPConditionalDirectiveRecord *PPRec;
102 Preprocessor &PP;
103 bool IsOutputFile;
104 bool FoundationIncluded;
105 llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls;
106 llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates;
107 llvm::StringSet<> WhiteListFilenames;
108
109 RetainSummaryManager &getSummaryManager(ASTContext &Ctx) {
110 if (!Summaries)
111 Summaries.reset(new RetainSummaryManager(Ctx,
112 /*TrackNSCFObjects=*/true,
113 /*trackOSObjects=*/false));
114 return *Summaries;
115 }
116
117 ObjCMigrateASTConsumer(StringRef migrateDir, unsigned astMigrateActions,
118 FileRemapper &remapper, FileManager &fileMgr,
119 const PPConditionalDirectiveRecord *PPRec,
120 Preprocessor &PP, bool isOutputFile,
121 ArrayRef<std::string> WhiteList)
122 : MigrateDir(migrateDir), ASTMigrateActions(astMigrateActions),
123 NSIntegerTypedefed(nullptr), NSUIntegerTypedefed(nullptr),
124 Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP),
125 IsOutputFile(isOutputFile), FoundationIncluded(false) {
126 // FIXME: StringSet should have insert(iter, iter) to use here.
127 for (const std::string &Val : WhiteList)
128 WhiteListFilenames.insert(Val);
129 }
130
131protected:
132 void Initialize(ASTContext &Context) override {
133 NSAPIObj.reset(new NSAPI(Context));
134 Editor.reset(new edit::EditedSource(Context.getSourceManager(),
135 Context.getLangOpts(),
136 PPRec));
137 }
138
139 bool HandleTopLevelDecl(DeclGroupRef DG) override {
140 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I)
141 migrateDecl(*I);
142 return true;
143 }
144 void HandleInterestingDecl(DeclGroupRef DG) override {
145 // Ignore decls from the PCH.
146 }
147 void HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) override {
148 ObjCMigrateASTConsumer::HandleTopLevelDecl(DG);
149 }
150
151 void HandleTranslationUnit(ASTContext &Ctx) override;
152
153 bool canModifyFile(StringRef Path) {
154 if (WhiteListFilenames.empty())
155 return true;
156 return WhiteListFilenames.find(llvm::sys::path::filename(Path))
157 != WhiteListFilenames.end();
158 }
159 bool canModifyFile(Optional<FileEntryRef> FE) {
160 if (!FE)
161 return false;
162 return canModifyFile(FE->getName());
163 }
164 bool canModifyFile(FileID FID) {
165 if (FID.isInvalid())
166 return false;
167 return canModifyFile(PP.getSourceManager().getFileEntryRefForID(FID));
168 }
169
170 bool canModify(const Decl *D) {
171 if (!D)
172 return false;
173 if (const ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(D))
174 return canModify(CatImpl->getCategoryDecl());
175 if (const ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(D))
176 return canModify(Impl->getClassInterface());
177 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
178 return canModify(cast<Decl>(MD->getDeclContext()));
179
180 FileID FID = PP.getSourceManager().getFileID(D->getLocation());
181 return canModifyFile(FID);
182 }
183};
184
185} // end anonymous namespace
186
187ObjCMigrateAction::ObjCMigrateAction(
188 std::unique_ptr<FrontendAction> WrappedAction, StringRef migrateDir,
189 unsigned migrateAction)
190 : WrapperFrontendAction(std::move(WrappedAction)), MigrateDir(migrateDir),
191 ObjCMigAction(migrateAction), CompInst(nullptr) {
192 if (MigrateDir.empty())
193 MigrateDir = "."; // user current directory if none is given.
194}
195
196std::unique_ptr<ASTConsumer>
197ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
198 PPConditionalDirectiveRecord *
199 PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager());
200 CI.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec));
201 std::vector<std::unique_ptr<ASTConsumer>> Consumers;
202 Consumers.push_back(WrapperFrontendAction::CreateASTConsumer(CI, InFile));
203 Consumers.push_back(std::make_unique<ObjCMigrateASTConsumer>(
204 MigrateDir, ObjCMigAction, Remapper, CompInst->getFileManager(), PPRec,
205 CompInst->getPreprocessor(), false, None));
206 return std::make_unique<MultiplexConsumer>(std::move(Consumers));
207}
208
209bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) {
210 Remapper.initFromDisk(MigrateDir, CI.getDiagnostics(),
211 /*ignoreIfFilesChanged=*/true);
212 CompInst = &CI;
213 CI.getDiagnostics().setIgnoreAllWarnings(true);
214 return true;
215}
216
217namespace {
218 // FIXME. This duplicates one in RewriteObjCFoundationAPI.cpp
219 bool subscriptOperatorNeedsParens(const Expr *FullExpr) {
220 const Expr* Expr = FullExpr->IgnoreImpCasts();
221 return !(isa<ArraySubscriptExpr>(Expr) || isa<CallExpr>(Expr) ||
222 isa<DeclRefExpr>(Expr) || isa<CXXNamedCastExpr>(Expr) ||
223 isa<CXXConstructExpr>(Expr) || isa<CXXThisExpr>(Expr) ||
224 isa<CXXTypeidExpr>(Expr) ||
225 isa<CXXUnresolvedConstructExpr>(Expr) ||
226 isa<ObjCMessageExpr>(Expr) || isa<ObjCPropertyRefExpr>(Expr) ||
227 isa<ObjCProtocolExpr>(Expr) || isa<MemberExpr>(Expr) ||
228 isa<ObjCIvarRefExpr>(Expr) || isa<ParenExpr>(FullExpr) ||
229 isa<ParenListExpr>(Expr) || isa<SizeOfPackExpr>(Expr));
230 }
231
232 /// - Rewrite message expression for Objective-C setter and getters into
233 /// property-dot syntax.
234 bool rewriteToPropertyDotSyntax(const ObjCMessageExpr *Msg,
235 Preprocessor &PP,
236 const NSAPI &NS, edit::Commit &commit,
237 const ParentMap *PMap) {
238 if (!Msg || Msg->isImplicit() ||
239 (Msg->getReceiverKind() != ObjCMessageExpr::Instance &&
240 Msg->getReceiverKind() != ObjCMessageExpr::SuperInstance))
241 return false;
242 if (const Expr *Receiver = Msg->getInstanceReceiver())
243 if (Receiver->getType()->isObjCBuiltinType())
244 return false;
245
246 const ObjCMethodDecl *Method = Msg->getMethodDecl();
247 if (!Method)
248 return false;
249 if (!Method->isPropertyAccessor())
250 return false;
251
252 const ObjCPropertyDecl *Prop = Method->findPropertyDecl();
253 if (!Prop)
254 return false;
255
256 SourceRange MsgRange = Msg->getSourceRange();
257 bool ReceiverIsSuper =
258 (Msg->getReceiverKind() == ObjCMessageExpr::SuperInstance);
259 // for 'super' receiver is nullptr.
260 const Expr *receiver = Msg->getInstanceReceiver();
261 bool NeedsParen =
262 ReceiverIsSuper ? false : subscriptOperatorNeedsParens(receiver);
263 bool IsGetter = (Msg->getNumArgs() == 0);
264 if (IsGetter) {
265 // Find space location range between receiver expression and getter method.
266 SourceLocation BegLoc =
267 ReceiverIsSuper ? Msg->getSuperLoc() : receiver->getEndLoc();
268 BegLoc = PP.getLocForEndOfToken(BegLoc);
269 SourceLocation EndLoc = Msg->getSelectorLoc(0);
270 SourceRange SpaceRange(BegLoc, EndLoc);
271 std::string PropertyDotString;
272 // rewrite getter method expression into: receiver.property or
273 // (receiver).property
274 if (NeedsParen) {
275 commit.insertBefore(receiver->getBeginLoc(), "(");
276 PropertyDotString = ").";
277 }
278 else
279 PropertyDotString = ".";
280 PropertyDotString += Prop->getName();
281 commit.replace(SpaceRange, PropertyDotString);
282
283 // remove '[' ']'
284 commit.replace(SourceRange(MsgRange.getBegin(), MsgRange.getBegin()), "");
285 commit.replace(SourceRange(MsgRange.getEnd(), MsgRange.getEnd()), "");
286 } else {
287 if (NeedsParen)
288 commit.insertWrap("(", receiver->getSourceRange(), ")");
289 std::string PropertyDotString = ".";
290 PropertyDotString += Prop->getName();
291 PropertyDotString += " =";
292 const Expr*const* Args = Msg->getArgs();
293 const Expr *RHS = Args[0];
294 if (!RHS)
295 return false;
296 SourceLocation BegLoc =
297 ReceiverIsSuper ? Msg->getSuperLoc() : receiver->getEndLoc();
298 BegLoc = PP.getLocForEndOfToken(BegLoc);
299 SourceLocation EndLoc = RHS->getBeginLoc();
300 EndLoc = EndLoc.getLocWithOffset(-1);
301 const char *colon = PP.getSourceManager().getCharacterData(EndLoc);
302 // Add a space after '=' if there is no space between RHS and '='
303 if (colon && colon[0] == ':')
304 PropertyDotString += " ";
305 SourceRange Range(BegLoc, EndLoc);
306 commit.replace(Range, PropertyDotString);
307 // remove '[' ']'
308 commit.replace(SourceRange(MsgRange.getBegin(), MsgRange.getBegin()), "");
309 commit.replace(SourceRange(MsgRange.getEnd(), MsgRange.getEnd()), "");
310 }
311 return true;
312 }
313
314class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> {
315 ObjCMigrateASTConsumer &Consumer;
316 ParentMap &PMap;
317
318public:
319 ObjCMigrator(ObjCMigrateASTConsumer &consumer, ParentMap &PMap)
320 : Consumer(consumer), PMap(PMap) { }
321
322 bool shouldVisitTemplateInstantiations() const { return false; }
323 bool shouldWalkTypesOfTypeLocs() const { return false; }
324
325 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
326 if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Literals) {
327 edit::Commit commit(*Consumer.Editor);
328 edit::rewriteToObjCLiteralSyntax(E, *Consumer.NSAPIObj, commit, &PMap);
329 Consumer.Editor->commit(commit);
330 }
331
332 if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_Subscripting) {
333 edit::Commit commit(*Consumer.Editor);
334 edit::rewriteToObjCSubscriptSyntax(E, *Consumer.NSAPIObj, commit);
335 Consumer.Editor->commit(commit);
336 }
337
338 if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_PropertyDotSyntax) {
339 edit::Commit commit(*Consumer.Editor);
340 rewriteToPropertyDotSyntax(E, Consumer.PP, *Consumer.NSAPIObj,
341 commit, &PMap);
342 Consumer.Editor->commit(commit);
343 }
344
345 return true;
346 }
347
348 bool TraverseObjCMessageExpr(ObjCMessageExpr *E) {
349 // Do depth first; we want to rewrite the subexpressions first so that if
350 // we have to move expressions we will move them already rewritten.
351 for (Stmt *SubStmt : E->children())
352 if (!TraverseStmt(SubStmt))
353 return false;
354
355 return WalkUpFromObjCMessageExpr(E);
356 }
357};
358
359class BodyMigrator : public RecursiveASTVisitor<BodyMigrator> {
360 ObjCMigrateASTConsumer &Consumer;
361 std::unique_ptr<ParentMap> PMap;
362
363public:
364 BodyMigrator(ObjCMigrateASTConsumer &consumer) : Consumer(consumer) { }
365
366 bool shouldVisitTemplateInstantiations() const { return false; }
367 bool shouldWalkTypesOfTypeLocs() const { return false; }
368
369 bool TraverseStmt(Stmt *S) {
370 PMap.reset(new ParentMap(S));
371 ObjCMigrator(Consumer, *PMap).TraverseStmt(S);
372 return true;
373 }
374};
375} // end anonymous namespace
376
377void ObjCMigrateASTConsumer::migrateDecl(Decl *D) {
378 if (!D)
379 return;
380 if (isa<ObjCMethodDecl>(D))
381 return; // Wait for the ObjC container declaration.
382
383 BodyMigrator(*this).TraverseDecl(D);
384}
385
386static void append_attr(std::string &PropertyString, const char *attr,
387 bool &LParenAdded) {
388 if (!LParenAdded) {
389 PropertyString += "(";
390 LParenAdded = true;
391 }
392 else
393 PropertyString += ", ";
394 PropertyString += attr;
395}
396
397static
398void MigrateBlockOrFunctionPointerTypeVariable(std::string & PropertyString,
399 const std::string& TypeString,
400 const char *name) {
401 const char *argPtr = TypeString.c_str();
402 int paren = 0;
403 while (*argPtr) {
404 switch (*argPtr) {
405 case '(':
406 PropertyString += *argPtr;
407 paren++;
408 break;
409 case ')':
410 PropertyString += *argPtr;
411 paren--;
412 break;
413 case '^':
414 case '*':
415 PropertyString += (*argPtr);
416 if (paren == 1) {
417 PropertyString += name;
418 name = "";
419 }
420 break;
421 default:
422 PropertyString += *argPtr;
423 break;
424 }
425 argPtr++;
426 }
427}
428
429static const char *PropertyMemoryAttribute(ASTContext &Context, QualType ArgType) {
430 Qualifiers::ObjCLifetime propertyLifetime = ArgType.getObjCLifetime();
431 bool RetainableObject = ArgType->isObjCRetainableType();
432 if (RetainableObject &&
433 (propertyLifetime == Qualifiers::OCL_Strong
434 || propertyLifetime == Qualifiers::OCL_None)) {
435 if (const ObjCObjectPointerType *ObjPtrTy =
436 ArgType->getAs<ObjCObjectPointerType>()) {
437 ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface();
438 if (IDecl &&
439 IDecl->lookupNestedProtocol(&Context.Idents.get("NSCopying")))
440 return "copy";
441 else
442 return "strong";
443 }
444 else if (ArgType->isBlockPointerType())
445 return "copy";
446 } else if (propertyLifetime == Qualifiers::OCL_Weak)
447 // TODO. More precise determination of 'weak' attribute requires
448 // looking into setter's implementation for backing weak ivar.
449 return "weak";
450 else if (RetainableObject)
451 return ArgType->isBlockPointerType() ? "copy" : "strong";
452 return nullptr;
453}
454
455static void rewriteToObjCProperty(const ObjCMethodDecl *Getter,
456 const ObjCMethodDecl *Setter,
457 const NSAPI &NS, edit::Commit &commit,
458 unsigned LengthOfPrefix,
459 bool Atomic, bool UseNsIosOnlyMacro,
460 bool AvailabilityArgsMatch) {
461 ASTContext &Context = NS.getASTContext();
462 bool LParenAdded = false;
463 std::string PropertyString = "@property ";
464 if (UseNsIosOnlyMacro && NS.isMacroDefined("NS_NONATOMIC_IOSONLY")) {
465 PropertyString += "(NS_NONATOMIC_IOSONLY";
466 LParenAdded = true;
467 } else if (!Atomic) {
468 PropertyString += "(nonatomic";
469 LParenAdded = true;
470 }
471
472 std::string PropertyNameString = Getter->getNameAsString();
473 StringRef PropertyName(PropertyNameString);
474 if (LengthOfPrefix > 0) {
475 if (!LParenAdded) {
476 PropertyString += "(getter=";
477 LParenAdded = true;
478 }
479 else
480 PropertyString += ", getter=";
481 PropertyString += PropertyNameString;
482 }
483 // Property with no setter may be suggested as a 'readonly' property.
484 if (!Setter)
485 append_attr(PropertyString, "readonly", LParenAdded);
486
487
488 // Short circuit 'delegate' properties that contain the name "delegate" or
489 // "dataSource", or have exact name "target" to have 'assign' attribute.
490 if (PropertyName.equals("target") ||
491 (PropertyName.find("delegate") != StringRef::npos) ||
492 (PropertyName.find("dataSource") != StringRef::npos)) {
493 QualType QT = Getter->getReturnType();
494 if (!QT->isRealType())
495 append_attr(PropertyString, "assign", LParenAdded);
496 } else if (!Setter) {
497 QualType ResType = Context.getCanonicalType(Getter->getReturnType());
498 if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ResType))
499 append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
500 } else {
501 const ParmVarDecl *argDecl = *Setter->param_begin();
502 QualType ArgType = Context.getCanonicalType(argDecl->getType());
503 if (const char *MemoryManagementAttr = PropertyMemoryAttribute(Context, ArgType))
504 append_attr(PropertyString, MemoryManagementAttr, LParenAdded);
505 }
506 if (LParenAdded)
507 PropertyString += ')';
508 QualType RT = Getter->getReturnType();
509 if (!isa<TypedefType>(RT)) {
510 // strip off any ARC lifetime qualifier.
511 QualType CanResultTy = Context.getCanonicalType(RT);
512 if (CanResultTy.getQualifiers().hasObjCLifetime()) {
513 Qualifiers Qs = CanResultTy.getQualifiers();
514 Qs.removeObjCLifetime();
515 RT = Context.getQualifiedType(CanResultTy.getUnqualifiedType(), Qs);
516 }
517 }
518 PropertyString += " ";
519 PrintingPolicy SubPolicy(Context.getPrintingPolicy());
520 SubPolicy.SuppressStrongLifetime = true;
521 SubPolicy.SuppressLifetimeQualifiers = true;
522 std::string TypeString = RT.getAsString(SubPolicy);
523 if (LengthOfPrefix > 0) {
524 // property name must strip off "is" and lower case the first character
525 // after that; e.g. isContinuous will become continuous.
526 StringRef PropertyNameStringRef(PropertyNameString);
527 PropertyNameStringRef = PropertyNameStringRef.drop_front(LengthOfPrefix);
528 PropertyNameString = std::string(PropertyNameStringRef);
529 bool NoLowering = (isUppercase(PropertyNameString[0]) &&
530 PropertyNameString.size() > 1 &&
531 isUppercase(PropertyNameString[1]));
532 if (!NoLowering)
533 PropertyNameString[0] = toLowercase(PropertyNameString[0]);
534 }
535 if (RT->isBlockPointerType() || RT->isFunctionPointerType())
536 MigrateBlockOrFunctionPointerTypeVariable(PropertyString,
537 TypeString,
538 PropertyNameString.c_str());
539 else {
540 char LastChar = TypeString[TypeString.size()-1];
541 PropertyString += TypeString;
542 if (LastChar != '*')
543 PropertyString += ' ';
544 PropertyString += PropertyNameString;
545 }
546 SourceLocation StartGetterSelectorLoc = Getter->getSelectorStartLoc();
547 Selector GetterSelector = Getter->getSelector();
548
549 SourceLocation EndGetterSelectorLoc =
550 StartGetterSelectorLoc.getLocWithOffset(GetterSelector.getNameForSlot(0).size());
551 commit.replace(CharSourceRange::getCharRange(Getter->getBeginLoc(),
552 EndGetterSelectorLoc),
553 PropertyString);
554 if (Setter && AvailabilityArgsMatch) {
555 SourceLocation EndLoc = Setter->getDeclaratorEndLoc();
556 // Get location past ';'
557 EndLoc = EndLoc.getLocWithOffset(1);
558 SourceLocation BeginOfSetterDclLoc = Setter->getBeginLoc();
559 // FIXME. This assumes that setter decl; is immediately preceded by eoln.
560 // It is trying to remove the setter method decl. line entirely.
561 BeginOfSetterDclLoc = BeginOfSetterDclLoc.getLocWithOffset(-1);
562 commit.remove(SourceRange(BeginOfSetterDclLoc, EndLoc));
563 }
564}
565
566static bool IsCategoryNameWithDeprecatedSuffix(ObjCContainerDecl *D) {
567 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(D)) {
568 StringRef Name = CatDecl->getName();
569 return Name.endswith("Deprecated");
570 }
571 return false;
572}
573
574void ObjCMigrateASTConsumer::migrateObjCContainerDecl(ASTContext &Ctx,
575 ObjCContainerDecl *D) {
576 if (D->isDeprecated() || IsCategoryNameWithDeprecatedSuffix(D))
577 return;
578
579 for (auto *Method : D->methods()) {
580 if (Method->isDeprecated())
581 continue;
582 bool PropertyInferred = migrateProperty(Ctx, D, Method);
583 // If a property is inferred, do not attempt to attach NS_RETURNS_INNER_POINTER to
584 // the getter method as it ends up on the property itself which we don't want
585 // to do unless -objcmt-returns-innerpointer-property option is on.
586 if (!PropertyInferred ||
587 (ASTMigrateActions & FrontendOptions::ObjCMT_ReturnsInnerPointerProperty))
588 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
589 migrateNsReturnsInnerPointer(Ctx, Method);
590 }
591 if (!(ASTMigrateActions & FrontendOptions::ObjCMT_ReturnsInnerPointerProperty))
592 return;
593
594 for (auto *Prop : D->instance_properties()) {
595 if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
596 !Prop->isDeprecated())
597 migratePropertyNsReturnsInnerPointer(Ctx, Prop);
598 }
599}
600
601static bool
602ClassImplementsAllMethodsAndProperties(ASTContext &Ctx,
603 const ObjCImplementationDecl *ImpDecl,
604 const ObjCInterfaceDecl *IDecl,
605 ObjCProtocolDecl *Protocol) {
606 // In auto-synthesis, protocol properties are not synthesized. So,
607 // a conforming protocol must have its required properties declared
608 // in class interface.
609 bool HasAtleastOneRequiredProperty = false;
610 if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition())
611 for (const auto *Property : PDecl->instance_properties()) {
612 if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional)
613 continue;
614 HasAtleastOneRequiredProperty = true;
615 DeclContext::lookup_result R = IDecl->lookup(Property->getDeclName());
616 if (R.empty()) {
617 // Relax the rule and look into class's implementation for a synthesize
618 // or dynamic declaration. Class is implementing a property coming from
619 // another protocol. This still makes the target protocol as conforming.
620 if (!ImpDecl->FindPropertyImplDecl(
621 Property->getDeclName().getAsIdentifierInfo(),
622 Property->getQueryKind()))
623 return false;
624 } else if (auto *ClassProperty = R.find_first<ObjCPropertyDecl>()) {
625 if ((ClassProperty->getPropertyAttributes() !=
626 Property->getPropertyAttributes()) ||
627 !Ctx.hasSameType(ClassProperty->getType(), Property->getType()))
628 return false;
629 } else
630 return false;
631 }
632
633 // At this point, all required properties in this protocol conform to those
634 // declared in the class.
635 // Check that class implements the required methods of the protocol too.
636 bool HasAtleastOneRequiredMethod = false;
637 if (const ObjCProtocolDecl *PDecl = Protocol->getDefinition()) {
638 if (PDecl->meth_begin() == PDecl->meth_end())
639 return HasAtleastOneRequiredProperty;
640 for (const auto *MD : PDecl->methods()) {
641 if (MD->isImplicit())
642 continue;
643 if (MD->getImplementationControl() == ObjCMethodDecl::Optional)
644 continue;
645 DeclContext::lookup_result R = ImpDecl->lookup(MD->getDeclName());
646 if (R.empty())
647 return false;
648 bool match = false;
649 HasAtleastOneRequiredMethod = true;
650 for (NamedDecl *ND : R)
651 if (ObjCMethodDecl *ImpMD = dyn_cast<ObjCMethodDecl>(ND))
652 if (Ctx.ObjCMethodsAreEqual(MD, ImpMD)) {
653 match = true;
654 break;
655 }
656 if (!match)
657 return false;
658 }
659 }
660 return HasAtleastOneRequiredProperty || HasAtleastOneRequiredMethod;
661}
662
663static bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl,
664 llvm::SmallVectorImpl<ObjCProtocolDecl*> &ConformingProtocols,
665 const NSAPI &NS, edit::Commit &commit) {
666 const ObjCList<ObjCProtocolDecl> &Protocols = IDecl->getReferencedProtocols();
667 std::string ClassString;
668 SourceLocation EndLoc =
669 IDecl->getSuperClass() ? IDecl->getSuperClassLoc() : IDecl->getLocation();
670
671 if (Protocols.empty()) {
672 ClassString = '<';
673 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
674 ClassString += ConformingProtocols[i]->getNameAsString();
675 if (i != (e-1))
676 ClassString += ", ";
677 }
678 ClassString += "> ";
679 }
680 else {
681 ClassString = ", ";
682 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
683 ClassString += ConformingProtocols[i]->getNameAsString();
684 if (i != (e-1))
685 ClassString += ", ";
686 }
687 ObjCInterfaceDecl::protocol_loc_iterator PL = IDecl->protocol_loc_end() - 1;
688 EndLoc = *PL;
689 }
690
691 commit.insertAfterToken(EndLoc, ClassString);
692 return true;
693}
694
695static StringRef GetUnsignedName(StringRef NSIntegerName) {
696 StringRef UnsignedName = llvm::StringSwitch<StringRef>(NSIntegerName)
697 .Case("int8_t", "uint8_t")
698 .Case("int16_t", "uint16_t")
699 .Case("int32_t", "uint32_t")
700 .Case("NSInteger", "NSUInteger")
701 .Case("int64_t", "uint64_t")
702 .Default(NSIntegerName);
703 return UnsignedName;
704}
705
706static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl,
707 const TypedefDecl *TypedefDcl,
708 const NSAPI &NS, edit::Commit &commit,
709 StringRef NSIntegerName,
710 bool NSOptions) {
711 std::string ClassString;
712 if (NSOptions) {
713 ClassString = "typedef NS_OPTIONS(";
714 ClassString += GetUnsignedName(NSIntegerName);
715 }
716 else {
717 ClassString = "typedef NS_ENUM(";
718 ClassString += NSIntegerName;
719 }
720 ClassString += ", ";
721
722 ClassString += TypedefDcl->getIdentifier()->getName();
723 ClassString += ')';
724 SourceRange R(EnumDcl->getBeginLoc(), EnumDcl->getBeginLoc());
725 commit.replace(R, ClassString);
726 SourceLocation EndOfEnumDclLoc = EnumDcl->getEndLoc();
727 EndOfEnumDclLoc = trans::findSemiAfterLocation(EndOfEnumDclLoc,
728 NS.getASTContext(), /*IsDecl*/true);
729 if (EndOfEnumDclLoc.isValid()) {
730 SourceRange EnumDclRange(EnumDcl->getBeginLoc(), EndOfEnumDclLoc);
731 commit.insertFromRange(TypedefDcl->getBeginLoc(), EnumDclRange);
732 }
733 else
734 return false;
735
736 SourceLocation EndTypedefDclLoc = TypedefDcl->getEndLoc();
737 EndTypedefDclLoc = trans::findSemiAfterLocation(EndTypedefDclLoc,
738 NS.getASTContext(), /*IsDecl*/true);
739 if (EndTypedefDclLoc.isValid()) {
740 SourceRange TDRange(TypedefDcl->getBeginLoc(), EndTypedefDclLoc);
741 commit.remove(TDRange);
742 }
743 else
744 return false;
745
746 EndOfEnumDclLoc =
747 trans::findLocationAfterSemi(EnumDcl->getEndLoc(), NS.getASTContext(),
748 /*IsDecl*/ true);
749 if (EndOfEnumDclLoc.isValid()) {
750 SourceLocation BeginOfEnumDclLoc = EnumDcl->getBeginLoc();
751 // FIXME. This assumes that enum decl; is immediately preceded by eoln.
752 // It is trying to remove the enum decl. lines entirely.
753 BeginOfEnumDclLoc = BeginOfEnumDclLoc.getLocWithOffset(-1);
754 commit.remove(SourceRange(BeginOfEnumDclLoc, EndOfEnumDclLoc));
755 return true;
756 }
757 return false;
758}
759
760static void rewriteToNSMacroDecl(ASTContext &Ctx,
761 const EnumDecl *EnumDcl,
762 const TypedefDecl *TypedefDcl,
763 const NSAPI &NS, edit::Commit &commit,
764 bool IsNSIntegerType) {
765 QualType DesignatedEnumType = EnumDcl->getIntegerType();
766 assert(!DesignatedEnumType.isNull()(static_cast<void> (0))
767 && "rewriteToNSMacroDecl - underlying enum type is null")(static_cast<void> (0));
768
769 PrintingPolicy Policy(Ctx.getPrintingPolicy());
770 std::string TypeString = DesignatedEnumType.getAsString(Policy);
771 std::string ClassString = IsNSIntegerType ? "NS_ENUM(" : "NS_OPTIONS(";
772 ClassString += TypeString;
773 ClassString += ", ";
774
775 ClassString += TypedefDcl->getIdentifier()->getName();
776 ClassString += ") ";
777 SourceLocation EndLoc = EnumDcl->getBraceRange().getBegin();
778 if (EndLoc.isInvalid())
779 return;
780 CharSourceRange R =
781 CharSourceRange::getCharRange(EnumDcl->getBeginLoc(), EndLoc);
782 commit.replace(R, ClassString);
783 // This is to remove spaces between '}' and typedef name.
784 SourceLocation StartTypedefLoc = EnumDcl->getEndLoc();
785 StartTypedefLoc = StartTypedefLoc.getLocWithOffset(+1);
786 SourceLocation EndTypedefLoc = TypedefDcl->getEndLoc();
787
788 commit.remove(SourceRange(StartTypedefLoc, EndTypedefLoc));
789}
790
791static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx,
792 const EnumDecl *EnumDcl) {
793 bool PowerOfTwo = true;
794 bool AllHexdecimalEnumerator = true;
795 uint64_t MaxPowerOfTwoVal = 0;
796 for (auto Enumerator : EnumDcl->enumerators()) {
797 const Expr *InitExpr = Enumerator->getInitExpr();
798 if (!InitExpr) {
799 PowerOfTwo = false;
800 AllHexdecimalEnumerator = false;
801 continue;
802 }
803 InitExpr = InitExpr->IgnoreParenCasts();
804 if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr))
805 if (BO->isShiftOp() || BO->isBitwiseOp())
806 return true;
807
808 uint64_t EnumVal = Enumerator->getInitVal().getZExtValue();
809 if (PowerOfTwo && EnumVal) {
810 if (!llvm::isPowerOf2_64(EnumVal))
811 PowerOfTwo = false;
812 else if (EnumVal > MaxPowerOfTwoVal)
813 MaxPowerOfTwoVal = EnumVal;
814 }
815 if (AllHexdecimalEnumerator && EnumVal) {
816 bool FoundHexdecimalEnumerator = false;
817 SourceLocation EndLoc = Enumerator->getEndLoc();
818 Token Tok;
819 if (!PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true))
820 if (Tok.isLiteral() && Tok.getLength() > 2) {
821 if (const char *StringLit = Tok.getLiteralData())
822 FoundHexdecimalEnumerator =
823 (StringLit[0] == '0' && (toLowercase(StringLit[1]) == 'x'));
824 }
825 if (!FoundHexdecimalEnumerator)
826 AllHexdecimalEnumerator = false;
827 }
828 }
829 return AllHexdecimalEnumerator || (PowerOfTwo && (MaxPowerOfTwoVal > 2));
830}
831
832void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx,
833 const ObjCImplementationDecl *ImpDecl) {
834 const ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface();
835 if (!IDecl || ObjCProtocolDecls.empty() || IDecl->isDeprecated())
836 return;
837 // Find all implicit conforming protocols for this class
838 // and make them explicit.
839 llvm::SmallPtrSet<ObjCProtocolDecl *, 8> ExplicitProtocols;
840 Ctx.CollectInheritedProtocols(IDecl, ExplicitProtocols);
841 llvm::SmallVector<ObjCProtocolDecl *, 8> PotentialImplicitProtocols;
842
843 for (ObjCProtocolDecl *ProtDecl : ObjCProtocolDecls)
844 if (!ExplicitProtocols.count(ProtDecl))
845 PotentialImplicitProtocols.push_back(ProtDecl);
846
847 if (PotentialImplicitProtocols.empty())
848 return;
849
850 // go through list of non-optional methods and properties in each protocol
851 // in the PotentialImplicitProtocols list. If class implements every one of the
852 // methods and properties, then this class conforms to this protocol.
853 llvm::SmallVector<ObjCProtocolDecl*, 8> ConformingProtocols;
854 for (unsigned i = 0, e = PotentialImplicitProtocols.size(); i != e; i++)
855 if (ClassImplementsAllMethodsAndProperties(Ctx, ImpDecl, IDecl,
856 PotentialImplicitProtocols[i]))
857 ConformingProtocols.push_back(PotentialImplicitProtocols[i]);
858
859 if (ConformingProtocols.empty())
860 return;
861
862 // Further reduce number of conforming protocols. If protocol P1 is in the list
863 // protocol P2 (P2<P1>), No need to include P1.
864 llvm::SmallVector<ObjCProtocolDecl*, 8> MinimalConformingProtocols;
865 for (unsigned i = 0, e = ConformingProtocols.size(); i != e; i++) {
866 bool DropIt = false;
867 ObjCProtocolDecl *TargetPDecl = ConformingProtocols[i];
868 for (unsigned i1 = 0, e1 = ConformingProtocols.size(); i1 != e1; i1++) {
869 ObjCProtocolDecl *PDecl = ConformingProtocols[i1];
870 if (PDecl == TargetPDecl)
871 continue;
872 if (PDecl->lookupProtocolNamed(
873 TargetPDecl->getDeclName().getAsIdentifierInfo())) {
874 DropIt = true;
875 break;
876 }
877 }
878 if (!DropIt)
879 MinimalConformingProtocols.push_back(TargetPDecl);
880 }
881 if (MinimalConformingProtocols.empty())
882 return;
883 edit::Commit commit(*Editor);
884 rewriteToObjCInterfaceDecl(IDecl, MinimalConformingProtocols,
885 *NSAPIObj, commit);
886 Editor->commit(commit);
887}
888
889void ObjCMigrateASTConsumer::CacheObjCNSIntegerTypedefed(
890 const TypedefDecl *TypedefDcl) {
891
892 QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
893 if (NSAPIObj->isObjCNSIntegerType(qt))
894 NSIntegerTypedefed = TypedefDcl;
895 else if (NSAPIObj->isObjCNSUIntegerType(qt))
896 NSUIntegerTypedefed = TypedefDcl;
897}
898
899bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx,
900 const EnumDecl *EnumDcl,
901 const TypedefDecl *TypedefDcl) {
902 if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() ||
903 EnumDcl->isDeprecated())
904 return false;
905 if (!TypedefDcl) {
906 if (NSIntegerTypedefed) {
907 TypedefDcl = NSIntegerTypedefed;
908 NSIntegerTypedefed = nullptr;
909 }
910 else if (NSUIntegerTypedefed) {
911 TypedefDcl = NSUIntegerTypedefed;
912 NSUIntegerTypedefed = nullptr;
913 }
914 else
915 return false;
916 FileID FileIdOfTypedefDcl =
917 PP.getSourceManager().getFileID(TypedefDcl->getLocation());
918 FileID FileIdOfEnumDcl =
919 PP.getSourceManager().getFileID(EnumDcl->getLocation());
920 if (FileIdOfTypedefDcl != FileIdOfEnumDcl)
921 return false;
922 }
923 if (TypedefDcl->isDeprecated())
924 return false;
925
926 QualType qt = TypedefDcl->getTypeSourceInfo()->getType();
927 StringRef NSIntegerName = NSAPIObj->GetNSIntegralKind(qt);
928
929 if (NSIntegerName.empty()) {
930 // Also check for typedef enum {...} TD;
931 if (const EnumType *EnumTy = qt->getAs<EnumType>()) {
932 if (EnumTy->getDecl() == EnumDcl) {
933 bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
934 if (!InsertFoundation(Ctx, TypedefDcl->getBeginLoc()))
935 return false;
936 edit::Commit commit(*Editor);
937 rewriteToNSMacroDecl(Ctx, EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions);
938 Editor->commit(commit);
939 return true;
940 }
941 }
942 return false;
943 }
944
945 // We may still use NS_OPTIONS based on what we find in the enumertor list.
946 bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl);
947 if (!InsertFoundation(Ctx, TypedefDcl->getBeginLoc()))
948 return false;
949 edit::Commit commit(*Editor);
950 bool Res = rewriteToNSEnumDecl(EnumDcl, TypedefDcl, *NSAPIObj,
951 commit, NSIntegerName, NSOptions);
952 Editor->commit(commit);
953 return Res;
954}
955
956static void ReplaceWithInstancetype(ASTContext &Ctx,
957 const ObjCMigrateASTConsumer &ASTC,
958 ObjCMethodDecl *OM) {
959 if (OM->getReturnType() == Ctx.getObjCInstanceType())
960 return; // already has instancetype.
961
962 SourceRange R;
963 std::string ClassString;
964 if (TypeSourceInfo *TSInfo = OM->getReturnTypeSourceInfo()) {
965 TypeLoc TL = TSInfo->getTypeLoc();
966 R = SourceRange(TL.getBeginLoc(), TL.getEndLoc());
967 ClassString = "instancetype";
968 }
969 else {
970 R = SourceRange(OM->getBeginLoc(), OM->getBeginLoc());
971 ClassString = OM->isInstanceMethod() ? '-' : '+';
972 ClassString += " (instancetype)";
973 }
974 edit::Commit commit(*ASTC.Editor);
975 commit.replace(R, ClassString);
976 ASTC.Editor->commit(commit);
977}
978
979static void ReplaceWithClasstype(const ObjCMigrateASTConsumer &ASTC,
980 ObjCMethodDecl *OM) {
981 ObjCInterfaceDecl *IDecl = OM->getClassInterface();
982 SourceRange R;
983 std::string ClassString;
984 if (TypeSourceInfo *TSInfo = OM->getReturnTypeSourceInfo()) {
985 TypeLoc TL = TSInfo->getTypeLoc();
986 R = SourceRange(TL.getBeginLoc(), TL.getEndLoc()); {
987 ClassString = std::string(IDecl->getName());
988 ClassString += "*";
989 }
990 }
991 else {
992 R = SourceRange(OM->getBeginLoc(), OM->getBeginLoc());
993 ClassString = "+ (";
994 ClassString += IDecl->getName(); ClassString += "*)";
995 }
996 edit::Commit commit(*ASTC.Editor);
997 commit.replace(R, ClassString);
998 ASTC.Editor->commit(commit);
999}
1000
1001void ObjCMigrateASTConsumer::migrateMethodInstanceType(ASTContext &Ctx,
1002 ObjCContainerDecl *CDecl,
1003 ObjCMethodDecl *OM) {
1004 ObjCInstanceTypeFamily OIT_Family =
1005 Selector::getInstTypeMethodFamily(OM->getSelector());
1006
1007 std::string ClassName;
1008 switch (OIT_Family) {
1009 case OIT_None:
1010 migrateFactoryMethod(Ctx, CDecl, OM);
1011 return;
1012 case OIT_Array:
1013 ClassName = "NSArray";
1014 break;
1015 case OIT_Dictionary:
1016 ClassName = "NSDictionary";
1017 break;
1018 case OIT_Singleton:
1019 migrateFactoryMethod(Ctx, CDecl, OM, OIT_Singleton);
1020 return;
1021 case OIT_Init:
1022 if (OM->getReturnType()->isObjCIdType())
1023 ReplaceWithInstancetype(Ctx, *this, OM);
1024 return;
1025 case OIT_ReturnsSelf:
1026 migrateFactoryMethod(Ctx, CDecl, OM, OIT_ReturnsSelf);
1027 return;
1028 }
1029 if (!OM->getReturnType()->isObjCIdType())
1030 return;
1031
1032 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
1033 if (!IDecl) {
1034 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
1035 IDecl = CatDecl->getClassInterface();
1036 else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
1037 IDecl = ImpDecl->getClassInterface();
1038 }
1039 if (!IDecl ||
1040 !IDecl->lookupInheritedClass(&Ctx.Idents.get(ClassName))) {
1041 migrateFactoryMethod(Ctx, CDecl, OM);
1042 return;
1043 }
1044 ReplaceWithInstancetype(Ctx, *this, OM);
1045}
1046
1047static bool TypeIsInnerPointer(QualType T) {
1048 if (!T->isAnyPointerType())
1049 return false;
1050 if (T->isObjCObjectPointerType() || T->isObjCBuiltinType() ||
1051 T->isBlockPointerType() || T->isFunctionPointerType() ||
1052 ento::coreFoundation::isCFObjectRef(T))
1053 return false;
1054 // Also, typedef-of-pointer-to-incomplete-struct is something that we assume
1055 // is not an innter pointer type.
1056 QualType OrigT = T;
1057 while (const TypedefType *TD = dyn_cast<TypedefType>(T.getTypePtr()))
1058 T = TD->getDecl()->getUnderlyingType();
1059 if (OrigT == T || !T->isPointerType())
1060 return true;
1061 const PointerType* PT = T->getAs<PointerType>();
1062 QualType UPointeeT = PT->getPointeeType().getUnqualifiedType();
1063 if (UPointeeT->isRecordType()) {
1064 const RecordType *RecordTy = UPointeeT->getAs<RecordType>();
1065 if (!RecordTy->getDecl()->isCompleteDefinition())
1066 return false;
1067 }
1068 return true;
1069}
1070
1071/// Check whether the two versions match.
1072static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y) {
1073 return (X == Y);
1074}
1075
1076/// AvailabilityAttrsMatch - This routine checks that if comparing two
1077/// availability attributes, all their components match. It returns
1078/// true, if not dealing with availability or when all components of
1079/// availability attributes match. This routine is only called when
1080/// the attributes are of the same kind.
1081static bool AvailabilityAttrsMatch(Attr *At1, Attr *At2) {
1082 const AvailabilityAttr *AA1 = dyn_cast<AvailabilityAttr>(At1);
1083 if (!AA1)
1084 return true;
1085 const AvailabilityAttr *AA2 = cast<AvailabilityAttr>(At2);
1086
1087 VersionTuple Introduced1 = AA1->getIntroduced();
1088 VersionTuple Deprecated1 = AA1->getDeprecated();
1089 VersionTuple Obsoleted1 = AA1->getObsoleted();
1090 bool IsUnavailable1 = AA1->getUnavailable();
1091 VersionTuple Introduced2 = AA2->getIntroduced();
1092 VersionTuple Deprecated2 = AA2->getDeprecated();
1093 VersionTuple Obsoleted2 = AA2->getObsoleted();
1094 bool IsUnavailable2 = AA2->getUnavailable();
1095 return (versionsMatch(Introduced1, Introduced2) &&
1096 versionsMatch(Deprecated1, Deprecated2) &&
1097 versionsMatch(Obsoleted1, Obsoleted2) &&
1098 IsUnavailable1 == IsUnavailable2);
1099}
1100
1101static bool MatchTwoAttributeLists(const AttrVec &Attrs1, const AttrVec &Attrs2,
1102 bool &AvailabilityArgsMatch) {
1103 // This list is very small, so this need not be optimized.
1104 for (unsigned i = 0, e = Attrs1.size(); i != e; i++) {
1105 bool match = false;
1106 for (unsigned j = 0, f = Attrs2.size(); j != f; j++) {
1107 // Matching attribute kind only. Except for Availability attributes,
1108 // we are not getting into details of the attributes. For all practical purposes
1109 // this is sufficient.
1110 if (Attrs1[i]->getKind() == Attrs2[j]->getKind()) {
1111 if (AvailabilityArgsMatch)
1112 AvailabilityArgsMatch = AvailabilityAttrsMatch(Attrs1[i], Attrs2[j]);
1113 match = true;
1114 break;
1115 }
1116 }
1117 if (!match)
1118 return false;
1119 }
1120 return true;
1121}
1122
1123/// AttributesMatch - This routine checks list of attributes for two
1124/// decls. It returns false, if there is a mismatch in kind of
1125/// attributes seen in the decls. It returns true if the two decls
1126/// have list of same kind of attributes. Furthermore, when there
1127/// are availability attributes in the two decls, it sets the
1128/// AvailabilityArgsMatch to false if availability attributes have
1129/// different versions, etc.
1130static bool AttributesMatch(const Decl *Decl1, const Decl *Decl2,
1131 bool &AvailabilityArgsMatch) {
1132 if (!Decl1->hasAttrs() || !Decl2->hasAttrs()) {
1133 AvailabilityArgsMatch = (Decl1->hasAttrs() == Decl2->hasAttrs());
1134 return true;
1135 }
1136 AvailabilityArgsMatch = true;
1137 const AttrVec &Attrs1 = Decl1->getAttrs();
1138 const AttrVec &Attrs2 = Decl2->getAttrs();
1139 bool match = MatchTwoAttributeLists(Attrs1, Attrs2, AvailabilityArgsMatch);
1140 if (match && (Attrs2.size() > Attrs1.size()))
1141 return MatchTwoAttributeLists(Attrs2, Attrs1, AvailabilityArgsMatch);
1142 return match;
1143}
1144
1145static bool IsValidIdentifier(ASTContext &Ctx,
1146 const char *Name) {
1147 if (!isIdentifierHead(Name[0]))
1148 return false;
1149 std::string NameString = Name;
1150 NameString[0] = toLowercase(NameString[0]);
1151 IdentifierInfo *II = &Ctx.Idents.get(NameString);
1152 return II->getTokenID() == tok::identifier;
1153}
1154
1155bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx,
1156 ObjCContainerDecl *D,
1157 ObjCMethodDecl *Method) {
1158 if (Method->isPropertyAccessor() || !Method->isInstanceMethod() ||
1159 Method->param_size() != 0)
1160 return false;
1161 // Is this method candidate to be a getter?
1162 QualType GRT = Method->getReturnType();
1163 if (GRT->isVoidType())
1164 return false;
1165
1166 Selector GetterSelector = Method->getSelector();
1167 ObjCInstanceTypeFamily OIT_Family =
1168 Selector::getInstTypeMethodFamily(GetterSelector);
1169
1170 if (OIT_Family != OIT_None)
1171 return false;
1172
1173 IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0);
1174 Selector SetterSelector =
1175 SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
1176 PP.getSelectorTable(),
1177 getterName);
1178 ObjCMethodDecl *SetterMethod = D->getInstanceMethod(SetterSelector);
1179 unsigned LengthOfPrefix = 0;
1180 if (!SetterMethod) {
1181 // try a different naming convention for getter: isXxxxx
1182 StringRef getterNameString = getterName->getName();
1183 bool IsPrefix = getterNameString.startswith("is");
1184 // Note that we don't want to change an isXXX method of retainable object
1185 // type to property (readonly or otherwise).
1186 if (IsPrefix && GRT->isObjCRetainableType())
1187 return false;
1188 if (IsPrefix || getterNameString.startswith("get")) {
1189 LengthOfPrefix = (IsPrefix ? 2 : 3);
1190 const char *CGetterName = getterNameString.data() + LengthOfPrefix;
1191 // Make sure that first character after "is" or "get" prefix can
1192 // start an identifier.
1193 if (!IsValidIdentifier(Ctx, CGetterName))
1194 return false;
1195 if (CGetterName[0] && isUppercase(CGetterName[0])) {
1196 getterName = &Ctx.Idents.get(CGetterName);
1197 SetterSelector =
1198 SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
1199 PP.getSelectorTable(),
1200 getterName);
1201 SetterMethod = D->getInstanceMethod(SetterSelector);
1202 }
1203 }
1204 }
1205
1206 if (SetterMethod) {
1207 if ((ASTMigrateActions & FrontendOptions::ObjCMT_ReadwriteProperty) == 0)
1208 return false;
1209 bool AvailabilityArgsMatch;
1210 if (SetterMethod->isDeprecated() ||
1211 !AttributesMatch(Method, SetterMethod, AvailabilityArgsMatch))
1212 return false;
1213
1214 // Is this a valid setter, matching the target getter?
1215 QualType SRT = SetterMethod->getReturnType();
1216 if (!SRT->isVoidType())
1217 return false;
1218 const ParmVarDecl *argDecl = *SetterMethod->param_begin();
1219 QualType ArgType = argDecl->getType();
1220 if (!Ctx.hasSameUnqualifiedType(ArgType, GRT))
1221 return false;
1222 edit::Commit commit(*Editor);
1223 rewriteToObjCProperty(Method, SetterMethod, *NSAPIObj, commit,
1224 LengthOfPrefix,
1225 (ASTMigrateActions &
1226 FrontendOptions::ObjCMT_AtomicProperty) != 0,
1227 (ASTMigrateActions &
1228 FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty) != 0,
1229 AvailabilityArgsMatch);
1230 Editor->commit(commit);
1231 return true;
1232 }
1233 else if (ASTMigrateActions & FrontendOptions::ObjCMT_ReadonlyProperty) {
1234 // Try a non-void method with no argument (and no setter or property of same name
1235 // as a 'readonly' property.
1236 edit::Commit commit(*Editor);
1237 rewriteToObjCProperty(Method, nullptr /*SetterMethod*/, *NSAPIObj, commit,
1238 LengthOfPrefix,
1239 (ASTMigrateActions &
1240 FrontendOptions::ObjCMT_AtomicProperty) != 0,
1241 (ASTMigrateActions &
1242 FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty) != 0,
1243 /*AvailabilityArgsMatch*/false);
1244 Editor->commit(commit);
1245 return true;
1246 }
1247 return false;
1248}
1249
1250void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx,
1251 ObjCMethodDecl *OM) {
1252 if (OM->isImplicit() ||
1253 !OM->isInstanceMethod() ||
1254 OM->hasAttr<ObjCReturnsInnerPointerAttr>())
1255 return;
1256
1257 QualType RT = OM->getReturnType();
1258 if (!TypeIsInnerPointer(RT) ||
1259 !NSAPIObj->isMacroDefined("NS_RETURNS_INNER_POINTER"))
1260 return;
1261
1262 edit::Commit commit(*Editor);
1263 commit.insertBefore(OM->getEndLoc(), " NS_RETURNS_INNER_POINTER");
1264 Editor->commit(commit);
1265}
1266
1267void ObjCMigrateASTConsumer::migratePropertyNsReturnsInnerPointer(ASTContext &Ctx,
1268 ObjCPropertyDecl *P) {
1269 QualType T = P->getType();
1270
1271 if (!TypeIsInnerPointer(T) ||
1272 !NSAPIObj->isMacroDefined("NS_RETURNS_INNER_POINTER"))
1273 return;
1274 edit::Commit commit(*Editor);
1275 commit.insertBefore(P->getEndLoc(), " NS_RETURNS_INNER_POINTER ");
1276 Editor->commit(commit);
1277}
1278
1279void ObjCMigrateASTConsumer::migrateAllMethodInstaceType(ASTContext &Ctx,
1280 ObjCContainerDecl *CDecl) {
1281 if (CDecl->isDeprecated() || IsCategoryNameWithDeprecatedSuffix(CDecl))
1282 return;
1283
1284 // migrate methods which can have instancetype as their result type.
1285 for (auto *Method : CDecl->methods()) {
1286 if (Method->isDeprecated())
1287 continue;
1288 migrateMethodInstanceType(Ctx, CDecl, Method);
1289 }
1290}
1291
1292void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx,
1293 ObjCContainerDecl *CDecl,
1294 ObjCMethodDecl *OM,
1295 ObjCInstanceTypeFamily OIT_Family) {
1296 if (OM->isInstanceMethod() ||
1297 OM->getReturnType() == Ctx.getObjCInstanceType() ||
1298 !OM->getReturnType()->isObjCIdType())
1299 return;
1300
1301 // Candidate factory methods are + (id) NaMeXXX : ... which belong to a class
1302 // NSYYYNamE with matching names be at least 3 characters long.
1303 ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
1304 if (!IDecl) {
1305 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CDecl))
1306 IDecl = CatDecl->getClassInterface();
1307 else if (ObjCImplDecl *ImpDecl = dyn_cast<ObjCImplDecl>(CDecl))
1308 IDecl = ImpDecl->getClassInterface();
1309 }
1310 if (!IDecl)
1311 return;
1312
1313 std::string StringClassName = std::string(IDecl->getName());
1314 StringRef LoweredClassName(StringClassName);
1315 std::string StringLoweredClassName = LoweredClassName.lower();
1316 LoweredClassName = StringLoweredClassName;
1317
1318 IdentifierInfo *MethodIdName = OM->getSelector().getIdentifierInfoForSlot(0);
1319 // Handle method with no name at its first selector slot; e.g. + (id):(int)x.
1320 if (!MethodIdName)
1321 return;
1322
1323 std::string MethodName = std::string(MethodIdName->getName());
1324 if (OIT_Family == OIT_Singleton || OIT_Family == OIT_ReturnsSelf) {
1325 StringRef STRefMethodName(MethodName);
1326 size_t len = 0;
1327 if (STRefMethodName.startswith("standard"))
1328 len = strlen("standard");
1329 else if (STRefMethodName.startswith("shared"))
1330 len = strlen("shared");
1331 else if (STRefMethodName.startswith("default"))
1332 len = strlen("default");
1333 else
1334 return;
1335 MethodName = std::string(STRefMethodName.substr(len));
1336 }
1337 std::string MethodNameSubStr = MethodName.substr(0, 3);
1338 StringRef MethodNamePrefix(MethodNameSubStr);
1339 std::string StringLoweredMethodNamePrefix = MethodNamePrefix.lower();
1340 MethodNamePrefix = StringLoweredMethodNamePrefix;
1341 size_t Ix = LoweredClassName.rfind(MethodNamePrefix);
1342 if (Ix == StringRef::npos)
1343 return;
1344 std::string ClassNamePostfix = std::string(LoweredClassName.substr(Ix));
1345 StringRef LoweredMethodName(MethodName);
1346 std::string StringLoweredMethodName = LoweredMethodName.lower();
1347 LoweredMethodName = StringLoweredMethodName;
1348 if (!LoweredMethodName.startswith(ClassNamePostfix))
1349 return;
1350 if (OIT_Family == OIT_ReturnsSelf)
1351 ReplaceWithClasstype(*this, OM);
1352 else
1353 ReplaceWithInstancetype(Ctx, *this, OM);
1354}
1355
1356static bool IsVoidStarType(QualType Ty) {
1357 if (!Ty->isPointerType())
1358 return false;
1359
1360 while (const TypedefType *TD = dyn_cast<TypedefType>(Ty.getTypePtr()))
1361 Ty = TD->getDecl()->getUnderlyingType();
1362
1363 // Is the type void*?
1364 const PointerType* PT = Ty->castAs<PointerType>();
1365 if (PT->getPointeeType().getUnqualifiedType()->isVoidType())
1366 return true;
1367 return IsVoidStarType(PT->getPointeeType());
1368}
1369
1370/// AuditedType - This routine audits the type AT and returns false if it is one of known
1371/// CF object types or of the "void *" variety. It returns true if we don't care about the type
1372/// such as a non-pointer or pointers which have no ownership issues (such as "int *").
1373static bool AuditedType (QualType AT) {
1374 if (!AT->isAnyPointerType() && !AT->isBlockPointerType())
1375 return true;
1376 // FIXME. There isn't much we can say about CF pointer type; or is there?
1377 if (ento::coreFoundation::isCFObjectRef(AT) ||
1378 IsVoidStarType(AT) ||
1379 // If an ObjC object is type, assuming that it is not a CF function and
1380 // that it is an un-audited function.
1381 AT->isObjCObjectPointerType() || AT->isObjCBuiltinType())
1382 return false;
1383 // All other pointers are assumed audited as harmless.
1384 return true;
1385}
1386
1387void ObjCMigrateASTConsumer::AnnotateImplicitBridging(ASTContext &Ctx) {
1388 if (CFFunctionIBCandidates.empty())
1389 return;
1390 if (!NSAPIObj->isMacroDefined("CF_IMPLICIT_BRIDGING_ENABLED")) {
1391 CFFunctionIBCandidates.clear();
1392 FileId = FileID();
1393 return;
1394 }
1395 // Insert CF_IMPLICIT_BRIDGING_ENABLE/CF_IMPLICIT_BRIDGING_DISABLED
1396 const Decl *FirstFD = CFFunctionIBCandidates[0];
1397 const Decl *LastFD =
1398 CFFunctionIBCandidates[CFFunctionIBCandidates.size()-1];
1399 const char *PragmaString = "\nCF_IMPLICIT_BRIDGING_ENABLED\n\n";
1400 edit::Commit commit(*Editor);
1401 commit.insertBefore(FirstFD->getBeginLoc(), PragmaString);
1402 PragmaString = "\n\nCF_IMPLICIT_BRIDGING_DISABLED\n";
1403 SourceLocation EndLoc = LastFD->getEndLoc();
1404 // get location just past end of function location.
1405 EndLoc = PP.getLocForEndOfToken(EndLoc);
1406 if (isa<FunctionDecl>(LastFD)) {
1407 // For Methods, EndLoc points to the ending semcolon. So,
1408 // not of these extra work is needed.
1409 Token Tok;
1410 // get locaiton of token that comes after end of function.
1411 bool Failed = PP.getRawToken(EndLoc, Tok, /*IgnoreWhiteSpace=*/true);
1412 if (!Failed)
1413 EndLoc = Tok.getLocation();
1414 }
1415 commit.insertAfterToken(EndLoc, PragmaString);
1416 Editor->commit(commit);
1417 FileId = FileID();
1418 CFFunctionIBCandidates.clear();
1419}
1420
1421void ObjCMigrateASTConsumer::migrateCFAnnotation(ASTContext &Ctx, const Decl *Decl) {
1422 if (Decl->isDeprecated())
1423 return;
1424
1425 if (Decl->hasAttr<CFAuditedTransferAttr>()) {
1426 assert(CFFunctionIBCandidates.empty() &&(static_cast<void> (0))
1427 "Cannot have audited functions/methods inside user "(static_cast<void> (0))
1428 "provided CF_IMPLICIT_BRIDGING_ENABLE")(static_cast<void> (0));
1429 return;
1430 }
1431
1432 // Finction must be annotated first.
1433 if (const FunctionDecl *FuncDecl = dyn_cast<FunctionDecl>(Decl)) {
1434 CF_BRIDGING_KIND AuditKind = migrateAddFunctionAnnotation(Ctx, FuncDecl);
1435 if (AuditKind == CF_BRIDGING_ENABLE) {
1436 CFFunctionIBCandidates.push_back(Decl);
1437 if (FileId.isInvalid())
1438 FileId = PP.getSourceManager().getFileID(Decl->getLocation());
1439 }
1440 else if (AuditKind == CF_BRIDGING_MAY_INCLUDE) {
1441 if (!CFFunctionIBCandidates.empty()) {
1442 CFFunctionIBCandidates.push_back(Decl);
1443 if (FileId.isInvalid())
1444 FileId = PP.getSourceManager().getFileID(Decl->getLocation());
1445 }
1446 }
1447 else
1448 AnnotateImplicitBridging(Ctx);
1449 }
1450 else {
1451 migrateAddMethodAnnotation(Ctx, cast<ObjCMethodDecl>(Decl));
1452 AnnotateImplicitBridging(Ctx);
1453 }
1454}
1455
1456void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
1457 const RetainSummary *RS,
1458 const FunctionDecl *FuncDecl,
1459 bool ResultAnnotated) {
1460 // Annotate function.
1461 if (!ResultAnnotated) {
1462 RetEffect Ret = RS->getRetEffect();
1463 const char *AnnotationString = nullptr;
1464 if (Ret.getObjKind() == ObjKind::CF) {
1465 if (Ret.isOwned() && NSAPIObj->isMacroDefined("CF_RETURNS_RETAINED"))
1466 AnnotationString = " CF_RETURNS_RETAINED";
1467 else if (Ret.notOwned() &&
1468 NSAPIObj->isMacroDefined("CF_RETURNS_NOT_RETAINED"))
1469 AnnotationString = " CF_RETURNS_NOT_RETAINED";
1470 }
1471 else if (Ret.getObjKind() == ObjKind::ObjC) {
1472 if (Ret.isOwned() && NSAPIObj->isMacroDefined("NS_RETURNS_RETAINED"))
1473 AnnotationString = " NS_RETURNS_RETAINED";
1474 }
1475
1476 if (AnnotationString) {
1477 edit::Commit commit(*Editor);
1478 commit.insertAfterToken(FuncDecl->getEndLoc(), AnnotationString);
1479 Editor->commit(commit);
1480 }
1481 }
1482 unsigned i = 0;
1483 for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
1484 pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
1485 const ParmVarDecl *pd = *pi;
1486 ArgEffect AE = RS->getArg(i);
1487 if (AE.getKind() == DecRef && AE.getObjKind() == ObjKind::CF &&
1488 !pd->hasAttr<CFConsumedAttr>() &&
1489 NSAPIObj->isMacroDefined("CF_CONSUMED")) {
1490 edit::Commit commit(*Editor);
1491 commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
1492 Editor->commit(commit);
1493 } else if (AE.getKind() == DecRef && AE.getObjKind() == ObjKind::ObjC &&
1494 !pd->hasAttr<NSConsumedAttr>() &&
1495 NSAPIObj->isMacroDefined("NS_CONSUMED")) {
1496 edit::Commit commit(*Editor);
1497 commit.insertBefore(pd->getLocation(), "NS_CONSUMED ");
1498 Editor->commit(commit);
1499 }
1500 }
1501}
1502
1503ObjCMigrateASTConsumer::CF_BRIDGING_KIND
1504 ObjCMigrateASTConsumer::migrateAddFunctionAnnotation(
1505 ASTContext &Ctx,
1506 const FunctionDecl *FuncDecl) {
1507 if (FuncDecl->hasBody())
1508 return CF_BRIDGING_NONE;
1509
1510 const RetainSummary *RS =
1511 getSummaryManager(Ctx).getSummary(AnyCall(FuncDecl));
1512 bool FuncIsReturnAnnotated = (FuncDecl->hasAttr<CFReturnsRetainedAttr>() ||
1513 FuncDecl->hasAttr<CFReturnsNotRetainedAttr>() ||
1514 FuncDecl->hasAttr<NSReturnsRetainedAttr>() ||
1515 FuncDecl->hasAttr<NSReturnsNotRetainedAttr>() ||
1516 FuncDecl->hasAttr<NSReturnsAutoreleasedAttr>());
1517
1518 // Trivial case of when function is annotated and has no argument.
1519 if (FuncIsReturnAnnotated && FuncDecl->getNumParams() == 0)
1520 return CF_BRIDGING_NONE;
1521
1522 bool ReturnCFAudited = false;
1523 if (!FuncIsReturnAnnotated) {
1524 RetEffect Ret = RS->getRetEffect();
1525 if (Ret.getObjKind() == ObjKind::CF &&
1526 (Ret.isOwned() || Ret.notOwned()))
1527 ReturnCFAudited = true;
1528 else if (!AuditedType(FuncDecl->getReturnType()))
1529 return CF_BRIDGING_NONE;
1530 }
1531
1532 // At this point result type is audited for potential inclusion.
1533 unsigned i = 0;
1534 bool ArgCFAudited = false;
1535 for (FunctionDecl::param_const_iterator pi = FuncDecl->param_begin(),
1536 pe = FuncDecl->param_end(); pi != pe; ++pi, ++i) {
1537 const ParmVarDecl *pd = *pi;
1538 ArgEffect AE = RS->getArg(i);
1539 if ((AE.getKind() == DecRef /*CFConsumed annotated*/ ||
1540 AE.getKind() == IncRef) && AE.getObjKind() == ObjKind::CF) {
1541 if (AE.getKind() == DecRef && !pd->hasAttr<CFConsumedAttr>())
1542 ArgCFAudited = true;
1543 else if (AE.getKind() == IncRef)
1544 ArgCFAudited = true;
1545 } else {
1546 QualType AT = pd->getType();
1547 if (!AuditedType(AT)) {
1548 AddCFAnnotations(Ctx, RS, FuncDecl, FuncIsReturnAnnotated);
1549 return CF_BRIDGING_NONE;
1550 }
1551 }
1552 }
1553 if (ReturnCFAudited || ArgCFAudited)
1554 return CF_BRIDGING_ENABLE;
1555
1556 return CF_BRIDGING_MAY_INCLUDE;
1557}
1558
1559void ObjCMigrateASTConsumer::migrateARCSafeAnnotation(ASTContext &Ctx,
1560 ObjCContainerDecl *CDecl) {
1561 if (!isa<ObjCInterfaceDecl>(CDecl) || CDecl->isDeprecated())
1562 return;
1563
1564 // migrate methods which can have instancetype as their result type.
1565 for (const auto *Method : CDecl->methods())
1566 migrateCFAnnotation(Ctx, Method);
1567}
1568
1569void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx,
1570 const RetainSummary *RS,
1571 const ObjCMethodDecl *MethodDecl,
1572 bool ResultAnnotated) {
1573 // Annotate function.
1574 if (!ResultAnnotated) {
1575 RetEffect Ret = RS->getRetEffect();
1576 const char *AnnotationString = nullptr;
1577 if (Ret.getObjKind() == ObjKind::CF) {
1578 if (Ret.isOwned() && NSAPIObj->isMacroDefined("CF_RETURNS_RETAINED"))
1579 AnnotationString = " CF_RETURNS_RETAINED";
1580 else if (Ret.notOwned() &&
1581 NSAPIObj->isMacroDefined("CF_RETURNS_NOT_RETAINED"))
1582 AnnotationString = " CF_RETURNS_NOT_RETAINED";
1583 }
1584 else if (Ret.getObjKind() == ObjKind::ObjC) {
1585 ObjCMethodFamily OMF = MethodDecl->getMethodFamily();
1586 switch (OMF) {
1587 case clang::OMF_alloc:
1588 case clang::OMF_new:
1589 case clang::OMF_copy:
1590 case clang::OMF_init:
1591 case clang::OMF_mutableCopy:
1592 break;
1593
1594 default:
1595 if (Ret.isOwned() && NSAPIObj->isMacroDefined("NS_RETURNS_RETAINED"))
1596 AnnotationString = " NS_RETURNS_RETAINED";
1597 break;
1598 }
1599 }
1600
1601 if (AnnotationString) {
1602 edit::Commit commit(*Editor);
1603 commit.insertBefore(MethodDecl->getEndLoc(), AnnotationString);
1604 Editor->commit(commit);
1605 }
1606 }
1607 unsigned i = 0;
1608 for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
1609 pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
1610 const ParmVarDecl *pd = *pi;
1611 ArgEffect AE = RS->getArg(i);
1612 if (AE.getKind() == DecRef
1613 && AE.getObjKind() == ObjKind::CF
1614 && !pd->hasAttr<CFConsumedAttr>() &&
1615 NSAPIObj->isMacroDefined("CF_CONSUMED")) {
1616 edit::Commit commit(*Editor);
1617 commit.insertBefore(pd->getLocation(), "CF_CONSUMED ");
1618 Editor->commit(commit);
1619 }
1620 }
1621}
1622
1623void ObjCMigrateASTConsumer::migrateAddMethodAnnotation(
1624 ASTContext &Ctx,
1625 const ObjCMethodDecl *MethodDecl) {
1626 if (MethodDecl->hasBody() || MethodDecl->isImplicit())
1627 return;
1628
1629 const RetainSummary *RS =
1630 getSummaryManager(Ctx).getSummary(AnyCall(MethodDecl));
1631
1632 bool MethodIsReturnAnnotated =
1633 (MethodDecl->hasAttr<CFReturnsRetainedAttr>() ||
1634 MethodDecl->hasAttr<CFReturnsNotRetainedAttr>() ||
1635 MethodDecl->hasAttr<NSReturnsRetainedAttr>() ||
1636 MethodDecl->hasAttr<NSReturnsNotRetainedAttr>() ||
1637 MethodDecl->hasAttr<NSReturnsAutoreleasedAttr>());
1638
1639 if (RS->getReceiverEffect().getKind() == DecRef &&
1640 !MethodDecl->hasAttr<NSConsumesSelfAttr>() &&
1641 MethodDecl->getMethodFamily() != OMF_init &&
1642 MethodDecl->getMethodFamily() != OMF_release &&
1643 NSAPIObj->isMacroDefined("NS_CONSUMES_SELF")) {
1644 edit::Commit commit(*Editor);
1645 commit.insertBefore(MethodDecl->getEndLoc(), " NS_CONSUMES_SELF");
1646 Editor->commit(commit);
1647 }
1648
1649 // Trivial case of when function is annotated and has no argument.
1650 if (MethodIsReturnAnnotated &&
1651 (MethodDecl->param_begin() == MethodDecl->param_end()))
1652 return;
1653
1654 if (!MethodIsReturnAnnotated) {
1655 RetEffect Ret = RS->getRetEffect();
1656 if ((Ret.getObjKind() == ObjKind::CF ||
1657 Ret.getObjKind() == ObjKind::ObjC) &&
1658 (Ret.isOwned() || Ret.notOwned())) {
1659 AddCFAnnotations(Ctx, RS, MethodDecl, false);
1660 return;
1661 } else if (!AuditedType(MethodDecl->getReturnType()))
1662 return;
1663 }
1664
1665 // At this point result type is either annotated or audited.
1666 unsigned i = 0;
1667 for (ObjCMethodDecl::param_const_iterator pi = MethodDecl->param_begin(),
1668 pe = MethodDecl->param_end(); pi != pe; ++pi, ++i) {
1669 const ParmVarDecl *pd = *pi;
1670 ArgEffect AE = RS->getArg(i);
1671 if ((AE.getKind() == DecRef && !pd->hasAttr<CFConsumedAttr>()) ||
1672 AE.getKind() == IncRef || !AuditedType(pd->getType())) {
1673 AddCFAnnotations(Ctx, RS, MethodDecl, MethodIsReturnAnnotated);
1674 return;
1675 }
1676 }
1677}
1678
1679namespace {
1680class SuperInitChecker : public RecursiveASTVisitor<SuperInitChecker> {
1681public:
1682 bool shouldVisitTemplateInstantiations() const { return false; }
1683 bool shouldWalkTypesOfTypeLocs() const { return false; }
1684
1685 bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
1686 if (E->getReceiverKind() == ObjCMessageExpr::SuperInstance) {
1687 if (E->getMethodFamily() == OMF_init)
1688 return false;
1689 }
1690 return true;
1691 }
1692};
1693} // end anonymous namespace
1694
1695static bool hasSuperInitCall(const ObjCMethodDecl *MD) {
1696 return !SuperInitChecker().TraverseStmt(MD->getBody());
1697}
1698
1699void ObjCMigrateASTConsumer::inferDesignatedInitializers(
1700 ASTContext &Ctx,
1701 const ObjCImplementationDecl *ImplD) {
1702
1703 const ObjCInterfaceDecl *IFace = ImplD->getClassInterface();
1704 if (!IFace || IFace->hasDesignatedInitializers())
1705 return;
1706 if (!NSAPIObj->isMacroDefined("NS_DESIGNATED_INITIALIZER"))
1707 return;
1708
1709 for (const auto *MD : ImplD->instance_methods()) {
1710 if (MD->isDeprecated() ||
1711 MD->getMethodFamily() != OMF_init ||
1712 MD->isDesignatedInitializerForTheInterface())
1713 continue;
1714 const ObjCMethodDecl *IFaceM = IFace->getMethod(MD->getSelector(),
1715 /*isInstance=*/true);
1716 if (!IFaceM)
1717 continue;
1718 if (hasSuperInitCall(MD)) {
1719 edit::Commit commit(*Editor);
1720 commit.insert(IFaceM->getEndLoc(), " NS_DESIGNATED_INITIALIZER");
1721 Editor->commit(commit);
1722 }
1723 }
1724}
1725
1726bool ObjCMigrateASTConsumer::InsertFoundation(ASTContext &Ctx,
1727 SourceLocation Loc) {
1728 if (FoundationIncluded)
1729 return true;
1730 if (Loc.isInvalid())
1731 return false;
1732 auto *nsEnumId = &Ctx.Idents.get("NS_ENUM");
1733 if (PP.getMacroDefinitionAtLoc(nsEnumId, Loc)) {
1734 FoundationIncluded = true;
1735 return true;
1736 }
1737 edit::Commit commit(*Editor);
1738 if (Ctx.getLangOpts().Modules)
1739 commit.insert(Loc, "#ifndef NS_ENUM\n@import Foundation;\n#endif\n");
1740 else
1741 commit.insert(Loc, "#ifndef NS_ENUM\n#import <Foundation/Foundation.h>\n#endif\n");
1742 Editor->commit(commit);
1743 FoundationIncluded = true;
1744 return true;
1745}
1746
1747namespace {
1748
1749class RewritesReceiver : public edit::EditsReceiver {
1750 Rewriter &Rewrite;
1751
1752public:
1753 RewritesReceiver(Rewriter &Rewrite) : Rewrite(Rewrite) { }
1754
1755 void insert(SourceLocation loc, StringRef text) override {
1756 Rewrite.InsertText(loc, text);
1757 }
1758 void replace(CharSourceRange range, StringRef text) override {
1759 Rewrite.ReplaceText(range.getBegin(), Rewrite.getRangeSize(range), text);
1760 }
1761};
1762
1763class JSONEditWriter : public edit::EditsReceiver {
1764 SourceManager &SourceMgr;
1765 llvm::raw_ostream &OS;
1766
1767public:
1768 JSONEditWriter(SourceManager &SM, llvm::raw_ostream &OS)
1769 : SourceMgr(SM), OS(OS) {
1770 OS << "[\n";
1771 }
1772 ~JSONEditWriter() override { OS << "]\n"; }
1773
1774private:
1775 struct EntryWriter {
1776 SourceManager &SourceMgr;
1777 llvm::raw_ostream &OS;
1778
1779 EntryWriter(SourceManager &SM, llvm::raw_ostream &OS)
1780 : SourceMgr(SM), OS(OS) {
1781 OS << " {\n";
1782 }
1783 ~EntryWriter() {
1784 OS << " },\n";
1785 }
1786
1787 void writeLoc(SourceLocation Loc) {
1788 FileID FID;
1789 unsigned Offset;
1790 std::tie(FID, Offset) = SourceMgr.getDecomposedLoc(Loc);
1791 assert(FID.isValid())(static_cast<void> (0));
1792 SmallString<200> Path =
1793 StringRef(SourceMgr.getFileEntryForID(FID)->getName());
1794 llvm::sys::fs::make_absolute(Path);
1795 OS << " \"file\": \"";
1796 OS.write_escaped(Path.str()) << "\",\n";
1797 OS << " \"offset\": " << Offset << ",\n";
1798 }
1799
1800 void writeRemove(CharSourceRange Range) {
1801 assert(Range.isCharRange())(static_cast<void> (0));
1802 std::pair<FileID, unsigned> Begin =
1803 SourceMgr.getDecomposedLoc(Range.getBegin());
1804 std::pair<FileID, unsigned> End =
1805 SourceMgr.getDecomposedLoc(Range.getEnd());
1806 assert(Begin.first == End.first)(static_cast<void> (0));
1807 assert(Begin.second <= End.second)(static_cast<void> (0));
1808 unsigned Length = End.second - Begin.second;
1809
1810 OS << " \"remove\": " << Length << ",\n";
1811 }
1812
1813 void writeText(StringRef Text) {
1814 OS << " \"text\": \"";
1815 OS.write_escaped(Text) << "\",\n";
1816 }
1817 };
1818
1819 void insert(SourceLocation Loc, StringRef Text) override {
1820 EntryWriter Writer(SourceMgr, OS);
1821 Writer.writeLoc(Loc);
1822 Writer.writeText(Text);
1823 }
1824
1825 void replace(CharSourceRange Range, StringRef Text) override {
1826 EntryWriter Writer(SourceMgr, OS);
1827 Writer.writeLoc(Range.getBegin());
1828 Writer.writeRemove(Range);
1829 Writer.writeText(Text);
1830 }
1831
1832 void remove(CharSourceRange Range) override {
1833 EntryWriter Writer(SourceMgr, OS);
1834 Writer.writeLoc(Range.getBegin());
1835 Writer.writeRemove(Range);
1836 }
1837};
1838
1839} // end anonymous namespace
1840
1841void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) {
1842
1843 TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl();
1844 if (ASTMigrateActions & FrontendOptions::ObjCMT_MigrateDecls) {
1
Assuming the condition is false
2
Taking false branch
1845 for (DeclContext::decl_iterator D = TU->decls_begin(), DEnd = TU->decls_end();
1846 D != DEnd; ++D) {
1847 FileID FID = PP.getSourceManager().getFileID((*D)->getLocation());
1848 if (FID.isValid())
1849 if (FileId.isValid() && FileId != FID) {
1850 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
1851 AnnotateImplicitBridging(Ctx);
1852 }
1853
1854 if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D))
1855 if (canModify(CDecl))
1856 migrateObjCContainerDecl(Ctx, CDecl);
1857 if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(*D)) {
1858 if (canModify(CatDecl))
1859 migrateObjCContainerDecl(Ctx, CatDecl);
1860 }
1861 else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D)) {
1862 ObjCProtocolDecls.insert(PDecl->getCanonicalDecl());
1863 if (canModify(PDecl))
1864 migrateObjCContainerDecl(Ctx, PDecl);
1865 }
1866 else if (const ObjCImplementationDecl *ImpDecl =
1867 dyn_cast<ObjCImplementationDecl>(*D)) {
1868 if ((ASTMigrateActions & FrontendOptions::ObjCMT_ProtocolConformance) &&
1869 canModify(ImpDecl))
1870 migrateProtocolConformance(Ctx, ImpDecl);
1871 }
1872 else if (const EnumDecl *ED = dyn_cast<EnumDecl>(*D)) {
1873 if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros))
1874 continue;
1875 if (!canModify(ED))
1876 continue;
1877 DeclContext::decl_iterator N = D;
1878 if (++N != DEnd) {
1879 const TypedefDecl *TD = dyn_cast<TypedefDecl>(*N);
1880 if (migrateNSEnumDecl(Ctx, ED, TD) && TD)
1881 D++;
1882 }
1883 else
1884 migrateNSEnumDecl(Ctx, ED, /*TypedefDecl */nullptr);
1885 }
1886 else if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(*D)) {
1887 if (!(ASTMigrateActions & FrontendOptions::ObjCMT_NsMacros))
1888 continue;
1889 if (!canModify(TD))
1890 continue;
1891 DeclContext::decl_iterator N = D;
1892 if (++N == DEnd)
1893 continue;
1894 if (const EnumDecl *ED = dyn_cast<EnumDecl>(*N)) {
1895 if (canModify(ED)) {
1896 if (++N != DEnd)
1897 if (const TypedefDecl *TDF = dyn_cast<TypedefDecl>(*N)) {
1898 // prefer typedef-follows-enum to enum-follows-typedef pattern.
1899 if (migrateNSEnumDecl(Ctx, ED, TDF)) {
1900 ++D; ++D;
1901 CacheObjCNSIntegerTypedefed(TD);
1902 continue;
1903 }
1904 }
1905 if (migrateNSEnumDecl(Ctx, ED, TD)) {
1906 ++D;
1907 continue;
1908 }
1909 }
1910 }
1911 CacheObjCNSIntegerTypedefed(TD);
1912 }
1913 else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*D)) {
1914 if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
1915 canModify(FD))
1916 migrateCFAnnotation(Ctx, FD);
1917 }
1918
1919 if (ObjCContainerDecl *CDecl = dyn_cast<ObjCContainerDecl>(*D)) {
1920 bool CanModify = canModify(CDecl);
1921 // migrate methods which can have instancetype as their result type.
1922 if ((ASTMigrateActions & FrontendOptions::ObjCMT_Instancetype) &&
1923 CanModify)
1924 migrateAllMethodInstaceType(Ctx, CDecl);
1925 // annotate methods with CF annotations.
1926 if ((ASTMigrateActions & FrontendOptions::ObjCMT_Annotation) &&
1927 CanModify)
1928 migrateARCSafeAnnotation(Ctx, CDecl);
1929 }
1930
1931 if (const ObjCImplementationDecl *
1932 ImplD = dyn_cast<ObjCImplementationDecl>(*D)) {
1933 if ((ASTMigrateActions & FrontendOptions::ObjCMT_DesignatedInitializer) &&
1934 canModify(ImplD))
1935 inferDesignatedInitializers(Ctx, ImplD);
1936 }
1937 }
1938 if (ASTMigrateActions & FrontendOptions::ObjCMT_Annotation)
1939 AnnotateImplicitBridging(Ctx);
1940 }
1941
1942 if (IsOutputFile) {
3
Assuming field 'IsOutputFile' is false
4
Taking false branch
1943 std::error_code EC;
1944 llvm::raw_fd_ostream OS(MigrateDir, EC, llvm::sys::fs::OF_None);
1945 if (EC) {
1946 DiagnosticsEngine &Diags = Ctx.getDiagnostics();
1947 Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0"))
1948 << EC.message();
1949 return;
1950 }
1951
1952 JSONEditWriter Writer(Ctx.getSourceManager(), OS);
1953 Editor->applyRewrites(Writer);
1954 return;
1955 }
1956
1957 Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts());
1958 RewritesReceiver Rec(rewriter);
1959 Editor->applyRewrites(Rec);
1960
1961 for (Rewriter::buffer_iterator
5
Loop condition is true. Entering loop body
1962 I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) {
1963 FileID FID = I->first;
1964 RewriteBuffer &buf = I->second;
1965 Optional<FileEntryRef> file = Ctx.getSourceManager().getFileEntryRefForID(FID);
6
Calling 'SourceManager::getFileEntryRefForID'
17
Returning from 'SourceManager::getFileEntryRefForID'
1966 assert(file)(static_cast<void> (0));
1967 SmallString<512> newText;
1968 llvm::raw_svector_ostream vecOS(newText);
1969 buf.write(vecOS);
1970 std::unique_ptr<llvm::MemoryBuffer> memBuf(
1971 llvm::MemoryBuffer::getMemBufferCopy(
1972 StringRef(newText.data(), newText.size()), file->getName()));
18
Calling 'FileEntryRef::getName'
1973 SmallString<64> filePath(file->getName());
1974 FileMgr.FixupRelativePath(filePath);
1975 Remapper.remap(filePath.str(), std::move(memBuf));
1976 }
1977
1978 if (IsOutputFile) {
1979 Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics());
1980 } else {
1981 Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics());
1982 }
1983}
1984
1985bool MigrateSourceAction::BeginInvocation(CompilerInstance &CI) {
1986 CI.getDiagnostics().setIgnoreAllWarnings(true);
1987 return true;
1988}
1989
1990static std::vector<std::string> getWhiteListFilenames(StringRef DirPath) {
1991 using namespace llvm::sys::fs;
1992 using namespace llvm::sys::path;
1993
1994 std::vector<std::string> Filenames;
1995 if (DirPath.empty() || !is_directory(DirPath))
1996 return Filenames;
1997
1998 std::error_code EC;
1999 directory_iterator DI = directory_iterator(DirPath, EC);
2000 directory_iterator DE;
2001 for (; !EC && DI != DE; DI = DI.increment(EC)) {
2002 if (is_regular_file(DI->path()))
2003 Filenames.push_back(std::string(filename(DI->path())));
2004 }
2005
2006 return Filenames;
2007}
2008
2009std::unique_ptr<ASTConsumer>
2010MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
2011 PPConditionalDirectiveRecord *
2012 PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager());
2013 unsigned ObjCMTAction = CI.getFrontendOpts().ObjCMTAction;
2014 unsigned ObjCMTOpts = ObjCMTAction;
2015 // These are companion flags, they do not enable transformations.
2016 ObjCMTOpts &= ~(FrontendOptions::ObjCMT_AtomicProperty |
2017 FrontendOptions::ObjCMT_NsAtomicIOSOnlyProperty);
2018 if (ObjCMTOpts == FrontendOptions::ObjCMT_None) {
2019 // If no specific option was given, enable literals+subscripting transforms
2020 // by default.
2021 ObjCMTAction |= FrontendOptions::ObjCMT_Literals |
2022 FrontendOptions::ObjCMT_Subscripting;
2023 }
2024 CI.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec));
2025 std::vector<std::string> WhiteList =
2026 getWhiteListFilenames(CI.getFrontendOpts().ObjCMTWhiteListPath);
2027 return std::make_unique<ObjCMigrateASTConsumer>(
2028 CI.getFrontendOpts().OutputFile, ObjCMTAction, Remapper,
2029 CI.getFileManager(), PPRec, CI.getPreprocessor(),
2030 /*isOutputFile=*/true, WhiteList);
2031}
2032
2033namespace {
2034struct EditEntry {
2035 Optional<FileEntryRef> File;
2036 unsigned Offset = 0;
2037 unsigned RemoveLen = 0;
2038 std::string Text;
2039};
2040} // end anonymous namespace
2041
2042namespace llvm {
2043template<> struct DenseMapInfo<EditEntry> {
2044 static inline EditEntry getEmptyKey() {
2045 EditEntry Entry;
2046 Entry.Offset = unsigned(-1);
2047 return Entry;
2048 }
2049 static inline EditEntry getTombstoneKey() {
2050 EditEntry Entry;
2051 Entry.Offset = unsigned(-2);
2052 return Entry;
2053 }
2054 static unsigned getHashValue(const EditEntry& Val) {
2055 return (unsigned)llvm::hash_combine(Val.File, Val.Offset, Val.RemoveLen,
2056 Val.Text);
2057 }
2058 static bool isEqual(const EditEntry &LHS, const EditEntry &RHS) {
2059 return LHS.File == RHS.File &&
2060 LHS.Offset == RHS.Offset &&
2061 LHS.RemoveLen == RHS.RemoveLen &&
2062 LHS.Text == RHS.Text;
2063 }
2064};
2065} // end namespace llvm
2066
2067namespace {
2068class RemapFileParser {
2069 FileManager &FileMgr;
2070
2071public:
2072 RemapFileParser(FileManager &FileMgr) : FileMgr(FileMgr) { }
2073
2074 bool parse(StringRef File, SmallVectorImpl<EditEntry> &Entries) {
2075 using namespace llvm::yaml;
2076
2077 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr =
2078 llvm::MemoryBuffer::getFile(File);
2079 if (!FileBufOrErr)
2080 return true;
2081
2082 llvm::SourceMgr SM;
2083 Stream YAMLStream(FileBufOrErr.get()->getMemBufferRef(), SM);
2084 document_iterator I = YAMLStream.begin();
2085 if (I == YAMLStream.end())
2086 return true;
2087 Node *Root = I->getRoot();
2088 if (!Root)
2089 return true;
2090
2091 SequenceNode *SeqNode = dyn_cast<SequenceNode>(Root);
2092 if (!SeqNode)
2093 return true;
2094
2095 for (SequenceNode::iterator
2096 AI = SeqNode->begin(), AE = SeqNode->end(); AI != AE; ++AI) {
2097 MappingNode *MapNode = dyn_cast<MappingNode>(&*AI);
2098 if (!MapNode)
2099 continue;
2100 parseEdit(MapNode, Entries);
2101 }
2102
2103 return false;
2104 }
2105
2106private:
2107 void parseEdit(llvm::yaml::MappingNode *Node,
2108 SmallVectorImpl<EditEntry> &Entries) {
2109 using namespace llvm::yaml;
2110 EditEntry Entry;
2111 bool Ignore = false;
2112
2113 for (MappingNode::iterator
2114 KVI = Node->begin(), KVE = Node->end(); KVI != KVE; ++KVI) {
2115 ScalarNode *KeyString = dyn_cast<ScalarNode>((*KVI).getKey());
2116 if (!KeyString)
2117 continue;
2118 SmallString<10> KeyStorage;
2119 StringRef Key = KeyString->getValue(KeyStorage);
2120
2121 ScalarNode *ValueString = dyn_cast<ScalarNode>((*KVI).getValue());
2122 if (!ValueString)
2123 continue;
2124 SmallString<64> ValueStorage;
2125 StringRef Val = ValueString->getValue(ValueStorage);
2126
2127 if (Key == "file") {
2128 if (auto File = FileMgr.getOptionalFileRef(Val))
2129 Entry.File = File;
2130 else
2131 Ignore = true;
2132 } else if (Key == "offset") {
2133 if (Val.getAsInteger(10, Entry.Offset))
2134 Ignore = true;
2135 } else if (Key == "remove") {
2136 if (Val.getAsInteger(10, Entry.RemoveLen))
2137 Ignore = true;
2138 } else if (Key == "text") {
2139 Entry.Text = std::string(Val);
2140 }
2141 }
2142
2143 if (!Ignore)
2144 Entries.push_back(Entry);
2145 }
2146};
2147} // end anonymous namespace
2148
2149static bool reportDiag(const Twine &Err, DiagnosticsEngine &Diag) {
2150 Diag.Report(Diag.getCustomDiagID(DiagnosticsEngine::Error, "%0"))
2151 << Err.str();
2152 return true;
2153}
2154
2155static std::string applyEditsToTemp(FileEntryRef FE,
2156 ArrayRef<EditEntry> Edits,
2157 FileManager &FileMgr,
2158 DiagnosticsEngine &Diag) {
2159 using namespace llvm::sys;
2160
2161 SourceManager SM(Diag, FileMgr);
2162 FileID FID = SM.createFileID(FE, SourceLocation(), SrcMgr::C_User);
2163 LangOptions LangOpts;
2164 edit::EditedSource Editor(SM, LangOpts);
2165 for (ArrayRef<EditEntry>::iterator
2166 I = Edits.begin(), E = Edits.end(); I != E; ++I) {
2167 const EditEntry &Entry = *I;
2168 assert(Entry.File == FE)(static_cast<void> (0));
2169 SourceLocation Loc =
2170 SM.getLocForStartOfFile(FID).getLocWithOffset(Entry.Offset);
2171 CharSourceRange Range;
2172 if (Entry.RemoveLen != 0) {
2173 Range = CharSourceRange::getCharRange(Loc,
2174 Loc.getLocWithOffset(Entry.RemoveLen));
2175 }
2176
2177 edit::Commit commit(Editor);
2178 if (Range.isInvalid()) {
2179 commit.insert(Loc, Entry.Text);
2180 } else if (Entry.Text.empty()) {
2181 commit.remove(Range);
2182 } else {
2183 commit.replace(Range, Entry.Text);
2184 }
2185 Editor.commit(commit);
2186 }
2187
2188 Rewriter rewriter(SM, LangOpts);
2189 RewritesReceiver Rec(rewriter);
2190 Editor.applyRewrites(Rec, /*adjustRemovals=*/false);
2191
2192 const RewriteBuffer *Buf = rewriter.getRewriteBufferFor(FID);
2193 SmallString<512> NewText;
2194 llvm::raw_svector_ostream OS(NewText);
2195 Buf->write(OS);
2196
2197 SmallString<64> TempPath;
2198 int FD;
2199 if (fs::createTemporaryFile(path::filename(FE.getName()),
2200 path::extension(FE.getName()).drop_front(), FD,
2201 TempPath)) {
2202 reportDiag("Could not create file: " + TempPath.str(), Diag);
2203 return std::string();
2204 }
2205
2206 llvm::raw_fd_ostream TmpOut(FD, /*shouldClose=*/true);
2207 TmpOut.write(NewText.data(), NewText.size());
2208 TmpOut.close();
2209
2210 return std::string(TempPath.str());
2211}
2212
2213bool arcmt::getFileRemappingsFromFileList(
2214 std::vector<std::pair<std::string,std::string> > &remap,
2215 ArrayRef<StringRef> remapFiles,
2216 DiagnosticConsumer *DiagClient) {
2217 bool hasErrorOccurred = false;
2218
2219 FileSystemOptions FSOpts;
2220 FileManager FileMgr(FSOpts);
2221 RemapFileParser Parser(FileMgr);
2222
2223 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
2224 IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
2225 new DiagnosticsEngine(DiagID, new DiagnosticOptions,
2226 DiagClient, /*ShouldOwnClient=*/false));
2227
2228 typedef llvm::DenseMap<FileEntryRef, std::vector<EditEntry> >
2229 FileEditEntriesTy;
2230 FileEditEntriesTy FileEditEntries;
2231
2232 llvm::DenseSet<EditEntry> EntriesSet;
2233
2234 for (ArrayRef<StringRef>::iterator
2235 I = remapFiles.begin(), E = remapFiles.end(); I != E; ++I) {
2236 SmallVector<EditEntry, 16> Entries;
2237 if (Parser.parse(*I, Entries))
2238 continue;
2239
2240 for (SmallVectorImpl<EditEntry>::iterator
2241 EI = Entries.begin(), EE = Entries.end(); EI != EE; ++EI) {
2242 EditEntry &Entry = *EI;
2243 if (!Entry.File)
2244 continue;
2245 std::pair<llvm::DenseSet<EditEntry>::iterator, bool>
2246 Insert = EntriesSet.insert(Entry);
2247 if (!Insert.second)
2248 continue;
2249
2250 FileEditEntries[*Entry.File].push_back(Entry);
2251 }
2252 }
2253
2254 for (FileEditEntriesTy::iterator
2255 I = FileEditEntries.begin(), E = FileEditEntries.end(); I != E; ++I) {
2256 std::string TempFile = applyEditsToTemp(I->first, I->second,
2257 FileMgr, *Diags);
2258 if (TempFile.empty()) {
2259 hasErrorOccurred = true;
2260 continue;
2261 }
2262
2263 remap.emplace_back(std::string(I->first.getName()), TempFile);
2264 }
2265
2266 return hasErrorOccurred;
2267}

/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/clang/include/clang/Basic/SourceManager.h

1//===- SourceManager.h - Track and cache source files -----------*- C++ -*-===//
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/// \file
10/// Defines the SourceManager interface.
11///
12/// There are three different types of locations in a %file: a spelling
13/// location, an expansion location, and a presumed location.
14///
15/// Given an example of:
16/// \code
17/// #define min(x, y) x < y ? x : y
18/// \endcode
19///
20/// and then later on a use of min:
21/// \code
22/// #line 17
23/// return min(a, b);
24/// \endcode
25///
26/// The expansion location is the line in the source code where the macro
27/// was expanded (the return statement), the spelling location is the
28/// location in the source where the macro was originally defined,
29/// and the presumed location is where the line directive states that
30/// the line is 17, or any other line.
31//
32//===----------------------------------------------------------------------===//
33
34#ifndef LLVM_CLANG_BASIC_SOURCEMANAGER_H
35#define LLVM_CLANG_BASIC_SOURCEMANAGER_H
36
37#include "clang/Basic/Diagnostic.h"
38#include "clang/Basic/FileEntry.h"
39#include "clang/Basic/SourceLocation.h"
40#include "llvm/ADT/ArrayRef.h"
41#include "llvm/ADT/BitVector.h"
42#include "llvm/ADT/DenseMap.h"
43#include "llvm/ADT/DenseSet.h"
44#include "llvm/ADT/IntrusiveRefCntPtr.h"
45#include "llvm/ADT/PointerIntPair.h"
46#include "llvm/ADT/SmallVector.h"
47#include "llvm/ADT/StringRef.h"
48#include "llvm/Support/Allocator.h"
49#include "llvm/Support/Compiler.h"
50#include "llvm/Support/MemoryBuffer.h"
51#include <cassert>
52#include <cstddef>
53#include <map>
54#include <memory>
55#include <string>
56#include <utility>
57#include <vector>
58
59namespace clang {
60
61class ASTReader;
62class ASTWriter;
63class FileManager;
64class LineTableInfo;
65class SourceManager;
66
67/// Public enums and private classes that are part of the
68/// SourceManager implementation.
69namespace SrcMgr {
70
71/// Indicates whether a file or directory holds normal user code,
72/// system code, or system code which is implicitly 'extern "C"' in C++ mode.
73///
74/// Entire directories can be tagged with this (this is maintained by
75/// DirectoryLookup and friends) as can specific FileInfos when a \#pragma
76/// system_header is seen or in various other cases.
77///
78enum CharacteristicKind {
79 C_User,
80 C_System,
81 C_ExternCSystem,
82 C_User_ModuleMap,
83 C_System_ModuleMap
84};
85
86/// Determine whether a file / directory characteristic is for system code.
87inline bool isSystem(CharacteristicKind CK) {
88 return CK != C_User && CK != C_User_ModuleMap;
89}
90
91/// Determine whether a file characteristic is for a module map.
92inline bool isModuleMap(CharacteristicKind CK) {
93 return CK == C_User_ModuleMap || CK == C_System_ModuleMap;
94}
95
96/// Mapping of line offsets into a source file. This does not own the storage
97/// for the line numbers.
98class LineOffsetMapping {
99public:
100 explicit operator bool() const { return Storage; }
101 unsigned size() const {
102 assert(Storage)(static_cast<void> (0));
103 return Storage[0];
104 }
105 ArrayRef<unsigned> getLines() const {
106 assert(Storage)(static_cast<void> (0));
107 return ArrayRef<unsigned>(Storage + 1, Storage + 1 + size());
108 }
109 const unsigned *begin() const { return getLines().begin(); }
110 const unsigned *end() const { return getLines().end(); }
111 const unsigned &operator[](int I) const { return getLines()[I]; }
112
113 static LineOffsetMapping get(llvm::MemoryBufferRef Buffer,
114 llvm::BumpPtrAllocator &Alloc);
115
116 LineOffsetMapping() = default;
117 LineOffsetMapping(ArrayRef<unsigned> LineOffsets,
118 llvm::BumpPtrAllocator &Alloc);
119
120private:
121 /// First element is the size, followed by elements at off-by-one indexes.
122 unsigned *Storage = nullptr;
123};
124
125/// One instance of this struct is kept for every file loaded or used.
126///
127/// This object owns the MemoryBuffer object.
128class alignas(8) ContentCache {
129 /// The actual buffer containing the characters from the input
130 /// file.
131 mutable std::unique_ptr<llvm::MemoryBuffer> Buffer;
132
133public:
134 /// Reference to the file entry representing this ContentCache.
135 ///
136 /// This reference does not own the FileEntry object.
137 ///
138 /// It is possible for this to be NULL if the ContentCache encapsulates
139 /// an imaginary text buffer.
140 ///
141 /// FIXME: Turn this into a FileEntryRef and remove Filename.
142 const FileEntry *OrigEntry;
143
144 /// References the file which the contents were actually loaded from.
145 ///
146 /// Can be different from 'Entry' if we overridden the contents of one file
147 /// with the contents of another file.
148 const FileEntry *ContentsEntry;
149
150 /// The filename that is used to access OrigEntry.
151 ///
152 /// FIXME: Remove this once OrigEntry is a FileEntryRef with a stable name.
153 StringRef Filename;
154
155 /// A bump pointer allocated array of offsets for each source line.
156 ///
157 /// This is lazily computed. The lines are owned by the SourceManager
158 /// BumpPointerAllocator object.
159 mutable LineOffsetMapping SourceLineCache;
160
161 /// Indicates whether the buffer itself was provided to override
162 /// the actual file contents.
163 ///
164 /// When true, the original entry may be a virtual file that does not
165 /// exist.
166 unsigned BufferOverridden : 1;
167
168 /// True if this content cache was initially created for a source file
169 /// considered to be volatile (likely to change between stat and open).
170 unsigned IsFileVolatile : 1;
171
172 /// True if this file may be transient, that is, if it might not
173 /// exist at some later point in time when this content entry is used,
174 /// after serialization and deserialization.
175 unsigned IsTransient : 1;
176
177 mutable unsigned IsBufferInvalid : 1;
178
179 ContentCache(const FileEntry *Ent = nullptr) : ContentCache(Ent, Ent) {}
180
181 ContentCache(const FileEntry *Ent, const FileEntry *contentEnt)
182 : OrigEntry(Ent), ContentsEntry(contentEnt), BufferOverridden(false),
183 IsFileVolatile(false), IsTransient(false), IsBufferInvalid(false) {}
184
185 /// The copy ctor does not allow copies where source object has either
186 /// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory
187 /// is not transferred, so this is a logical error.
188 ContentCache(const ContentCache &RHS)
189 : BufferOverridden(false), IsFileVolatile(false), IsTransient(false),
190 IsBufferInvalid(false) {
191 OrigEntry = RHS.OrigEntry;
192 ContentsEntry = RHS.ContentsEntry;
193
194 assert(!RHS.Buffer && !RHS.SourceLineCache &&(static_cast<void> (0))
195 "Passed ContentCache object cannot own a buffer.")(static_cast<void> (0));
196 }
197
198 ContentCache &operator=(const ContentCache &RHS) = delete;
199
200 /// Returns the memory buffer for the associated content.
201 ///
202 /// \param Diag Object through which diagnostics will be emitted if the
203 /// buffer cannot be retrieved.
204 ///
205 /// \param Loc If specified, is the location that invalid file diagnostics
206 /// will be emitted at.
207 llvm::Optional<llvm::MemoryBufferRef>
208 getBufferOrNone(DiagnosticsEngine &Diag, FileManager &FM,
209 SourceLocation Loc = SourceLocation()) const;
210
211 /// Returns the size of the content encapsulated by this
212 /// ContentCache.
213 ///
214 /// This can be the size of the source file or the size of an
215 /// arbitrary scratch buffer. If the ContentCache encapsulates a source
216 /// file this size is retrieved from the file's FileEntry.
217 unsigned getSize() const;
218
219 /// Returns the number of bytes actually mapped for this
220 /// ContentCache.
221 ///
222 /// This can be 0 if the MemBuffer was not actually expanded.
223 unsigned getSizeBytesMapped() const;
224
225 /// Returns the kind of memory used to back the memory buffer for
226 /// this content cache. This is used for performance analysis.
227 llvm::MemoryBuffer::BufferKind getMemoryBufferKind() const;
228
229 /// Return the buffer, only if it has been loaded.
230 llvm::Optional<llvm::MemoryBufferRef> getBufferIfLoaded() const {
231 if (Buffer)
232 return Buffer->getMemBufferRef();
233 return None;
234 }
235
236 /// Return a StringRef to the source buffer data, only if it has already
237 /// been loaded.
238 llvm::Optional<StringRef> getBufferDataIfLoaded() const {
239 if (Buffer)
240 return Buffer->getBuffer();
241 return None;
242 }
243
244 /// Set the buffer.
245 void setBuffer(std::unique_ptr<llvm::MemoryBuffer> B) {
246 IsBufferInvalid = false;
247 Buffer = std::move(B);
248 }
249
250 /// Set the buffer to one that's not owned (or to nullptr).
251 ///
252 /// \pre Buffer cannot already be set.
253 void setUnownedBuffer(llvm::Optional<llvm::MemoryBufferRef> B) {
254 assert(!Buffer && "Expected to be called right after construction")(static_cast<void> (0));
255 if (B)
256 setBuffer(llvm::MemoryBuffer::getMemBuffer(*B));
257 }
258
259 // If BufStr has an invalid BOM, returns the BOM name; otherwise, returns
260 // nullptr
261 static const char *getInvalidBOM(StringRef BufStr);
262};
263
264// Assert that the \c ContentCache objects will always be 8-byte aligned so
265// that we can pack 3 bits of integer into pointers to such objects.
266static_assert(alignof(ContentCache) >= 8,
267 "ContentCache must be 8-byte aligned.");
268
269/// Information about a FileID, basically just the logical file
270/// that it represents and include stack information.
271///
272/// Each FileInfo has include stack information, indicating where it came
273/// from. This information encodes the \#include chain that a token was
274/// expanded from. The main include file has an invalid IncludeLoc.
275///
276/// FileInfo should not grow larger than ExpansionInfo. Doing so will
277/// cause memory to bloat in compilations with many unloaded macro
278/// expansions, since the two data structurs are stored in a union in
279/// SLocEntry. Extra fields should instead go in "ContentCache *", which
280/// stores file contents and other bits on the side.
281///
282class FileInfo {
283 friend class clang::SourceManager;
284 friend class clang::ASTWriter;
285 friend class clang::ASTReader;
286
287 /// The location of the \#include that brought in this file.
288 ///
289 /// This is an invalid SLOC for the main file (top of the \#include chain).
290 SourceLocation IncludeLoc;
291
292 /// Number of FileIDs (files and macros) that were created during
293 /// preprocessing of this \#include, including this SLocEntry.
294 ///
295 /// Zero means the preprocessor didn't provide such info for this SLocEntry.
296 unsigned NumCreatedFIDs : 31;
297
298 /// Whether this FileInfo has any \#line directives.
299 unsigned HasLineDirectives : 1;
300
301 /// The content cache and the characteristic of the file.
302 llvm::PointerIntPair<const ContentCache *, 3, CharacteristicKind>
303 ContentAndKind;
304
305public:
306 /// Return a FileInfo object.
307 static FileInfo get(SourceLocation IL, ContentCache &Con,
308 CharacteristicKind FileCharacter, StringRef Filename) {
309 FileInfo X;
310 X.IncludeLoc = IL;
311 X.NumCreatedFIDs = 0;
312 X.HasLineDirectives = false;
313 X.ContentAndKind.setPointer(&Con);
314 X.ContentAndKind.setInt(FileCharacter);
315 Con.Filename = Filename;
316 return X;
317 }
318
319 SourceLocation getIncludeLoc() const {
320 return IncludeLoc;
321 }
322
323 const ContentCache &getContentCache() const {
324 return *ContentAndKind.getPointer();
325 }
326
327 /// Return whether this is a system header or not.
328 CharacteristicKind getFileCharacteristic() const {
329 return ContentAndKind.getInt();
330 }
331
332 /// Return true if this FileID has \#line directives in it.
333 bool hasLineDirectives() const { return HasLineDirectives; }
334
335 /// Set the flag that indicates that this FileID has
336 /// line table entries associated with it.
337 void setHasLineDirectives() { HasLineDirectives = true; }
338
339 /// Returns the name of the file that was used when the file was loaded from
340 /// the underlying file system.
341 StringRef getName() const { return getContentCache().Filename; }
342};
343
344/// Each ExpansionInfo encodes the expansion location - where
345/// the token was ultimately expanded, and the SpellingLoc - where the actual
346/// character data for the token came from.
347class ExpansionInfo {
348 // Really these are all SourceLocations.
349
350 /// Where the spelling for the token can be found.
351 SourceLocation SpellingLoc;
352
353 /// In a macro expansion, ExpansionLocStart and ExpansionLocEnd
354 /// indicate the start and end of the expansion. In object-like macros,
355 /// they will be the same. In a function-like macro expansion, the start
356 /// will be the identifier and the end will be the ')'. Finally, in
357 /// macro-argument instantiations, the end will be 'SourceLocation()', an
358 /// invalid location.
359 SourceLocation ExpansionLocStart, ExpansionLocEnd;
360
361 /// Whether the expansion range is a token range.
362 bool ExpansionIsTokenRange;
363
364public:
365 SourceLocation getSpellingLoc() const {
366 return SpellingLoc.isInvalid() ? getExpansionLocStart() : SpellingLoc;
367 }
368
369 SourceLocation getExpansionLocStart() const {
370 return ExpansionLocStart;
371 }
372
373 SourceLocation getExpansionLocEnd() const {
374 return ExpansionLocEnd.isInvalid() ? getExpansionLocStart()
375 : ExpansionLocEnd;
376 }
377
378 bool isExpansionTokenRange() const { return ExpansionIsTokenRange; }
379
380 CharSourceRange getExpansionLocRange() const {
381 return CharSourceRange(
382 SourceRange(getExpansionLocStart(), getExpansionLocEnd()),
383 isExpansionTokenRange());
384 }
385
386 bool isMacroArgExpansion() const {
387 // Note that this needs to return false for default constructed objects.
388 return getExpansionLocStart().isValid() && ExpansionLocEnd.isInvalid();
389 }
390
391 bool isMacroBodyExpansion() const {
392 return getExpansionLocStart().isValid() && ExpansionLocEnd.isValid();
393 }
394
395 bool isFunctionMacroExpansion() const {
396 return getExpansionLocStart().isValid() &&
397 getExpansionLocStart() != getExpansionLocEnd();
398 }
399
400 /// Return a ExpansionInfo for an expansion.
401 ///
402 /// Start and End specify the expansion range (where the macro is
403 /// expanded), and SpellingLoc specifies the spelling location (where
404 /// the characters from the token come from). All three can refer to
405 /// normal File SLocs or expansion locations.
406 static ExpansionInfo create(SourceLocation SpellingLoc, SourceLocation Start,
407 SourceLocation End,
408 bool ExpansionIsTokenRange = true) {
409 ExpansionInfo X;
410 X.SpellingLoc = SpellingLoc;
411 X.ExpansionLocStart = Start;
412 X.ExpansionLocEnd = End;
413 X.ExpansionIsTokenRange = ExpansionIsTokenRange;
414 return X;
415 }
416
417 /// Return a special ExpansionInfo for the expansion of
418 /// a macro argument into a function-like macro's body.
419 ///
420 /// ExpansionLoc specifies the expansion location (where the macro is
421 /// expanded). This doesn't need to be a range because a macro is always
422 /// expanded at a macro parameter reference, and macro parameters are
423 /// always exactly one token. SpellingLoc specifies the spelling location
424 /// (where the characters from the token come from). ExpansionLoc and
425 /// SpellingLoc can both refer to normal File SLocs or expansion locations.
426 ///
427 /// Given the code:
428 /// \code
429 /// #define F(x) f(x)
430 /// F(42);
431 /// \endcode
432 ///
433 /// When expanding '\c F(42)', the '\c x' would call this with an
434 /// SpellingLoc pointing at '\c 42' and an ExpansionLoc pointing at its
435 /// location in the definition of '\c F'.
436 static ExpansionInfo createForMacroArg(SourceLocation SpellingLoc,
437 SourceLocation ExpansionLoc) {
438 // We store an intentionally invalid source location for the end of the
439 // expansion range to mark that this is a macro argument location rather
440 // than a normal one.
441 return create(SpellingLoc, ExpansionLoc, SourceLocation());
442 }
443
444 /// Return a special ExpansionInfo representing a token that ends
445 /// prematurely. This is used to model a '>>' token that has been split
446 /// into '>' tokens and similar cases. Unlike for the other forms of
447 /// expansion, the expansion range in this case is a character range, not
448 /// a token range.
449 static ExpansionInfo createForTokenSplit(SourceLocation SpellingLoc,
450 SourceLocation Start,
451 SourceLocation End) {
452 return create(SpellingLoc, Start, End, false);
453 }
454};
455
456// Assert that the \c FileInfo objects are no bigger than \c ExpansionInfo
457// objects. This controls the size of \c SLocEntry, of which we have one for
458// each macro expansion. The number of (unloaded) macro expansions can be
459// very large. Any other fields needed in FileInfo should go in ContentCache.
460static_assert(sizeof(FileInfo) <= sizeof(ExpansionInfo),
461 "FileInfo must be no larger than ExpansionInfo.");
462
463/// This is a discriminated union of FileInfo and ExpansionInfo.
464///
465/// SourceManager keeps an array of these objects, and they are uniquely
466/// identified by the FileID datatype.
467class SLocEntry {
468 static constexpr int OffsetBits = 8 * sizeof(SourceLocation::UIntTy) - 1;
469 SourceLocation::UIntTy Offset : OffsetBits;
470 SourceLocation::UIntTy IsExpansion : 1;
471 union {
472 FileInfo File;
473 ExpansionInfo Expansion;
474 };
475
476public:
477 SLocEntry() : Offset(), IsExpansion(), File() {}
478
479 SourceLocation::UIntTy getOffset() const { return Offset; }
480
481 bool isExpansion() const { return IsExpansion; }
482 bool isFile() const { return !isExpansion(); }
483
484 const FileInfo &getFile() const {
485 assert(isFile() && "Not a file SLocEntry!")(static_cast<void> (0));
486 return File;
487 }
488
489 const ExpansionInfo &getExpansion() const {
490 assert(isExpansion() && "Not a macro expansion SLocEntry!")(static_cast<void> (0));
491 return Expansion;
492 }
493
494 static SLocEntry get(SourceLocation::UIntTy Offset, const FileInfo &FI) {
495 assert(!(Offset & (1ULL << OffsetBits)) && "Offset is too large")(static_cast<void> (0));
496 SLocEntry E;
497 E.Offset = Offset;
498 E.IsExpansion = false;
499 E.File = FI;
500 return E;
501 }
502
503 static SLocEntry get(SourceLocation::UIntTy Offset,
504 const ExpansionInfo &Expansion) {
505 assert(!(Offset & (1ULL << OffsetBits)) && "Offset is too large")(static_cast<void> (0));
506 SLocEntry E;
507 E.Offset = Offset;
508 E.IsExpansion = true;
509 new (&E.Expansion) ExpansionInfo(Expansion);
510 return E;
511 }
512};
513
514} // namespace SrcMgr
515
516/// External source of source location entries.
517class ExternalSLocEntrySource {
518public:
519 virtual ~ExternalSLocEntrySource();
520
521 /// Read the source location entry with index ID, which will always be
522 /// less than -1.
523 ///
524 /// \returns true if an error occurred that prevented the source-location
525 /// entry from being loaded.
526 virtual bool ReadSLocEntry(int ID) = 0;
527
528 /// Retrieve the module import location and name for the given ID, if
529 /// in fact it was loaded from a module (rather than, say, a precompiled
530 /// header).
531 virtual std::pair<SourceLocation, StringRef> getModuleImportLoc(int ID) = 0;
532};
533
534/// Holds the cache used by isBeforeInTranslationUnit.
535///
536/// The cache structure is complex enough to be worth breaking out of
537/// SourceManager.
538class InBeforeInTUCacheEntry {
539 /// The FileID's of the cached query.
540 ///
541 /// If these match up with a subsequent query, the result can be reused.
542 FileID LQueryFID, RQueryFID;
543
544 /// True if LQueryFID was created before RQueryFID.
545 ///
546 /// This is used to compare macro expansion locations.
547 bool IsLQFIDBeforeRQFID;
548
549 /// The file found in common between the two \#include traces, i.e.,
550 /// the nearest common ancestor of the \#include tree.
551 FileID CommonFID;
552
553 /// The offset of the previous query in CommonFID.
554 ///
555 /// Usually, this represents the location of the \#include for QueryFID, but
556 /// if LQueryFID is a parent of RQueryFID (or vice versa) then these can be a
557 /// random token in the parent.
558 unsigned LCommonOffset, RCommonOffset;
559
560public:
561 /// Return true if the currently cached values match up with
562 /// the specified LHS/RHS query.
563 ///
564 /// If not, we can't use the cache.
565 bool isCacheValid(FileID LHS, FileID RHS) const {
566 return LQueryFID == LHS && RQueryFID == RHS;
567 }
568
569 /// If the cache is valid, compute the result given the
570 /// specified offsets in the LHS/RHS FileID's.
571 bool getCachedResult(unsigned LOffset, unsigned ROffset) const {
572 // If one of the query files is the common file, use the offset. Otherwise,
573 // use the #include loc in the common file.
574 if (LQueryFID != CommonFID) LOffset = LCommonOffset;
575 if (RQueryFID != CommonFID) ROffset = RCommonOffset;
576
577 // It is common for multiple macro expansions to be "included" from the same
578 // location (expansion location), in which case use the order of the FileIDs
579 // to determine which came first. This will also take care the case where
580 // one of the locations points at the inclusion/expansion point of the other
581 // in which case its FileID will come before the other.
582 if (LOffset == ROffset)
583 return IsLQFIDBeforeRQFID;
584
585 return LOffset < ROffset;
586 }
587
588 /// Set up a new query.
589 void setQueryFIDs(FileID LHS, FileID RHS, bool isLFIDBeforeRFID) {
590 assert(LHS != RHS)(static_cast<void> (0));
591 LQueryFID = LHS;
592 RQueryFID = RHS;
593 IsLQFIDBeforeRQFID = isLFIDBeforeRFID;
594 }
595
596 void clear() {
597 LQueryFID = RQueryFID = FileID();
598 IsLQFIDBeforeRQFID = false;
599 }
600
601 void setCommonLoc(FileID commonFID, unsigned lCommonOffset,
602 unsigned rCommonOffset) {
603 CommonFID = commonFID;
604 LCommonOffset = lCommonOffset;
605 RCommonOffset = rCommonOffset;
606 }
607};
608
609/// The stack used when building modules on demand, which is used
610/// to provide a link between the source managers of the different compiler
611/// instances.
612using ModuleBuildStack = ArrayRef<std::pair<std::string, FullSourceLoc>>;
613
614/// This class handles loading and caching of source files into memory.
615///
616/// This object owns the MemoryBuffer objects for all of the loaded
617/// files and assigns unique FileID's for each unique \#include chain.
618///
619/// The SourceManager can be queried for information about SourceLocation
620/// objects, turning them into either spelling or expansion locations. Spelling
621/// locations represent where the bytes corresponding to a token came from and
622/// expansion locations represent where the location is in the user's view. In
623/// the case of a macro expansion, for example, the spelling location indicates
624/// where the expanded token came from and the expansion location specifies
625/// where it was expanded.
626class SourceManager : public RefCountedBase<SourceManager> {
627 /// DiagnosticsEngine object.
628 DiagnosticsEngine &Diag;
629
630 FileManager &FileMgr;
631
632 mutable llvm::BumpPtrAllocator ContentCacheAlloc;
633
634 /// Memoized information about all of the files tracked by this
635 /// SourceManager.
636 ///
637 /// This map allows us to merge ContentCache entries based
638 /// on their FileEntry*. All ContentCache objects will thus have unique,
639 /// non-null, FileEntry pointers.
640 llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*> FileInfos;
641
642 /// True if the ContentCache for files that are overridden by other
643 /// files, should report the original file name. Defaults to true.
644 bool OverridenFilesKeepOriginalName = true;
645
646 /// True if non-system source files should be treated as volatile
647 /// (likely to change while trying to use them). Defaults to false.
648 bool UserFilesAreVolatile;
649
650 /// True if all files read during this compilation should be treated
651 /// as transient (may not be present in later compilations using a module
652 /// file created from this compilation). Defaults to false.
653 bool FilesAreTransient = false;
654
655 struct OverriddenFilesInfoTy {
656 /// Files that have been overridden with the contents from another
657 /// file.
658 llvm::DenseMap<const FileEntry *, const FileEntry *> OverriddenFiles;
659
660 /// Files that were overridden with a memory buffer.
661 llvm::DenseSet<const FileEntry *> OverriddenFilesWithBuffer;
662 };
663
664 /// Lazily create the object keeping overridden files info, since
665 /// it is uncommonly used.
666 std::unique_ptr<OverriddenFilesInfoTy> OverriddenFilesInfo;
667
668 OverriddenFilesInfoTy &getOverriddenFilesInfo() {
669 if (!OverriddenFilesInfo)
670 OverriddenFilesInfo.reset(new OverriddenFilesInfoTy);
671 return *OverriddenFilesInfo;
672 }
673
674 /// Information about various memory buffers that we have read in.
675 ///
676 /// All FileEntry* within the stored ContentCache objects are NULL,
677 /// as they do not refer to a file.
678 std::vector<SrcMgr::ContentCache*> MemBufferInfos;
679
680 /// The table of SLocEntries that are local to this module.
681 ///
682 /// Positive FileIDs are indexes into this table. Entry 0 indicates an invalid
683 /// expansion.
684 SmallVector<SrcMgr::SLocEntry, 0> LocalSLocEntryTable;
685
686 /// The table of SLocEntries that are loaded from other modules.
687 ///
688 /// Negative FileIDs are indexes into this table. To get from ID to an index,
689 /// use (-ID - 2).
690 SmallVector<SrcMgr::SLocEntry, 0> LoadedSLocEntryTable;
691
692 /// The starting offset of the next local SLocEntry.
693 ///
694 /// This is LocalSLocEntryTable.back().Offset + the size of that entry.
695 SourceLocation::UIntTy NextLocalOffset;
696
697 /// The starting offset of the latest batch of loaded SLocEntries.
698 ///
699 /// This is LoadedSLocEntryTable.back().Offset, except that that entry might
700 /// not have been loaded, so that value would be unknown.
701 SourceLocation::UIntTy CurrentLoadedOffset;
702
703 /// The highest possible offset is 2^32-1 (2^63-1 for 64-bit source
704 /// locations), so CurrentLoadedOffset starts at 2^31 (2^63 resp.).
705 static const SourceLocation::UIntTy MaxLoadedOffset =
706 1ULL << (8 * sizeof(SourceLocation::UIntTy) - 1);
707
708 /// A bitmap that indicates whether the entries of LoadedSLocEntryTable
709 /// have already been loaded from the external source.
710 ///
711 /// Same indexing as LoadedSLocEntryTable.
712 llvm::BitVector SLocEntryLoaded;
713
714 /// An external source for source location entries.
715 ExternalSLocEntrySource *ExternalSLocEntries = nullptr;
716
717 /// A one-entry cache to speed up getFileID.
718 ///
719 /// LastFileIDLookup records the last FileID looked up or created, because it
720 /// is very common to look up many tokens from the same file.
721 mutable FileID LastFileIDLookup;
722
723 /// Holds information for \#line directives.
724 ///
725 /// This is referenced by indices from SLocEntryTable.
726 std::unique_ptr<LineTableInfo> LineTable;
727
728 /// These ivars serve as a cache used in the getLineNumber
729 /// method which is used to speedup getLineNumber calls to nearby locations.
730 mutable FileID LastLineNoFileIDQuery;
731 mutable const SrcMgr::ContentCache *LastLineNoContentCache;
732 mutable unsigned LastLineNoFilePos;
733 mutable unsigned LastLineNoResult;
734
735 /// The file ID for the main source file of the translation unit.
736 FileID MainFileID;
737
738 /// The file ID for the precompiled preamble there is one.
739 FileID PreambleFileID;
740
741 // Statistics for -print-stats.
742 mutable unsigned NumLinearScans = 0;
743 mutable unsigned NumBinaryProbes = 0;
744
745 /// Associates a FileID with its "included/expanded in" decomposed
746 /// location.
747 ///
748 /// Used to cache results from and speed-up \c getDecomposedIncludedLoc
749 /// function.
750 mutable llvm::DenseMap<FileID, std::pair<FileID, unsigned>> IncludedLocMap;
751
752 /// The key value into the IsBeforeInTUCache table.
753 using IsBeforeInTUCacheKey = std::pair<FileID, FileID>;
754
755 /// The IsBeforeInTranslationUnitCache is a mapping from FileID pairs
756 /// to cache results.
757 using InBeforeInTUCache =
758 llvm::DenseMap<IsBeforeInTUCacheKey, InBeforeInTUCacheEntry>;
759
760 /// Cache results for the isBeforeInTranslationUnit method.
761 mutable InBeforeInTUCache IBTUCache;
762 mutable InBeforeInTUCacheEntry IBTUCacheOverflow;
763
764 /// Return the cache entry for comparing the given file IDs
765 /// for isBeforeInTranslationUnit.
766 InBeforeInTUCacheEntry &getInBeforeInTUCache(FileID LFID, FileID RFID) const;
767
768 // Cache for the "fake" buffer used for error-recovery purposes.
769 mutable std::unique_ptr<llvm::MemoryBuffer> FakeBufferForRecovery;
770
771 mutable std::unique_ptr<SrcMgr::ContentCache> FakeContentCacheForRecovery;
772
773 mutable std::unique_ptr<SrcMgr::SLocEntry> FakeSLocEntryForRecovery;
774
775 /// Lazily computed map of macro argument chunks to their expanded
776 /// source location.
777 using MacroArgsMap = std::map<unsigned, SourceLocation>;
778
779 mutable llvm::DenseMap<FileID, std::unique_ptr<MacroArgsMap>>
780 MacroArgsCacheMap;
781
782 /// The stack of modules being built, which is used to detect
783 /// cycles in the module dependency graph as modules are being built, as
784 /// well as to describe why we're rebuilding a particular module.
785 ///
786 /// There is no way to set this value from the command line. If we ever need
787 /// to do so (e.g., if on-demand module construction moves out-of-process),
788 /// we can add a cc1-level option to do so.
789 SmallVector<std::pair<std::string, FullSourceLoc>, 2> StoredModuleBuildStack;
790
791public:
792 SourceManager(DiagnosticsEngine &Diag, FileManager &FileMgr,
793 bool UserFilesAreVolatile = false);
794 explicit SourceManager(const SourceManager &) = delete;
795 SourceManager &operator=(const SourceManager &) = delete;
796 ~SourceManager();
797
798 void clearIDTables();
799
800 /// Initialize this source manager suitably to replay the compilation
801 /// described by \p Old. Requires that \p Old outlive \p *this.
802 void initializeForReplay(const SourceManager &Old);
803
804 DiagnosticsEngine &getDiagnostics() const { return Diag; }
805
806 FileManager &getFileManager() const { return FileMgr; }
807
808 /// Set true if the SourceManager should report the original file name
809 /// for contents of files that were overridden by other files. Defaults to
810 /// true.
811 void setOverridenFilesKeepOriginalName(bool value) {
812 OverridenFilesKeepOriginalName = value;
813 }
814
815 /// True if non-system source files should be treated as volatile
816 /// (likely to change while trying to use them).
817 bool userFilesAreVolatile() const { return UserFilesAreVolatile; }
818
819 /// Retrieve the module build stack.
820 ModuleBuildStack getModuleBuildStack() const {
821 return StoredModuleBuildStack;
822 }
823
824 /// Set the module build stack.
825 void setModuleBuildStack(ModuleBuildStack stack) {
826 StoredModuleBuildStack.clear();
827 StoredModuleBuildStack.append(stack.begin(), stack.end());
828 }
829
830 /// Push an entry to the module build stack.
831 void pushModuleBuildStack(StringRef moduleName, FullSourceLoc importLoc) {
832 StoredModuleBuildStack.push_back(std::make_pair(moduleName.str(),importLoc));
833 }
834
835 //===--------------------------------------------------------------------===//
836 // MainFileID creation and querying methods.
837 //===--------------------------------------------------------------------===//
838
839 /// Returns the FileID of the main source file.
840 FileID getMainFileID() const { return MainFileID; }
841
842 /// Set the file ID for the main source file.
843 void setMainFileID(FileID FID) {
844 MainFileID = FID;
845 }
846
847 /// Returns true when the given FileEntry corresponds to the main file.
848 ///
849 /// The main file should be set prior to calling this function.
850 bool isMainFile(const FileEntry &SourceFile);
851
852 /// Set the file ID for the precompiled preamble.
853 void setPreambleFileID(FileID Preamble) {
854 assert(PreambleFileID.isInvalid() && "PreambleFileID already set!")(static_cast<void> (0));
855 PreambleFileID = Preamble;
856 }
857
858 /// Get the file ID for the precompiled preamble if there is one.
859 FileID getPreambleFileID() const { return PreambleFileID; }
860
861 //===--------------------------------------------------------------------===//
862 // Methods to create new FileID's and macro expansions.
863 //===--------------------------------------------------------------------===//
864
865 /// Create a new FileID that represents the specified file
866 /// being \#included from the specified IncludePosition.
867 ///
868 /// This translates NULL into standard input.
869 FileID createFileID(const FileEntry *SourceFile, SourceLocation IncludePos,
870 SrcMgr::CharacteristicKind FileCharacter,
871 int LoadedID = 0,
872 SourceLocation::UIntTy LoadedOffset = 0);
873
874 FileID createFileID(FileEntryRef SourceFile, SourceLocation IncludePos,
875 SrcMgr::CharacteristicKind FileCharacter,
876 int LoadedID = 0,
877 SourceLocation::UIntTy LoadedOffset = 0);
878
879 /// Create a new FileID that represents the specified memory buffer.
880 ///
881 /// This does no caching of the buffer and takes ownership of the
882 /// MemoryBuffer, so only pass a MemoryBuffer to this once.
883 FileID createFileID(std::unique_ptr<llvm::MemoryBuffer> Buffer,
884 SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User,
885 int LoadedID = 0, SourceLocation::UIntTy LoadedOffset = 0,
886 SourceLocation IncludeLoc = SourceLocation());
887
888 /// Create a new FileID that represents the specified memory buffer.
889 ///
890 /// This does not take ownership of the MemoryBuffer. The memory buffer must
891 /// outlive the SourceManager.
892 FileID createFileID(const llvm::MemoryBufferRef &Buffer,
893 SrcMgr::CharacteristicKind FileCharacter = SrcMgr::C_User,
894 int LoadedID = 0, SourceLocation::UIntTy LoadedOffset = 0,
895 SourceLocation IncludeLoc = SourceLocation());
896
897 /// Get the FileID for \p SourceFile if it exists. Otherwise, create a
898 /// new FileID for the \p SourceFile.
899 FileID getOrCreateFileID(const FileEntry *SourceFile,
900 SrcMgr::CharacteristicKind FileCharacter);
901
902 /// Return a new SourceLocation that encodes the
903 /// fact that a token from SpellingLoc should actually be referenced from
904 /// ExpansionLoc, and that it represents the expansion of a macro argument
905 /// into the function-like macro body.
906 SourceLocation createMacroArgExpansionLoc(SourceLocation Loc,
907 SourceLocation ExpansionLoc,
908 unsigned TokLength);
909
910 /// Return a new SourceLocation that encodes the fact
911 /// that a token from SpellingLoc should actually be referenced from
912 /// ExpansionLoc.
913 SourceLocation
914 createExpansionLoc(SourceLocation Loc, SourceLocation ExpansionLocStart,
915 SourceLocation ExpansionLocEnd, unsigned TokLength,
916 bool ExpansionIsTokenRange = true, int LoadedID = 0,
917 SourceLocation::UIntTy LoadedOffset = 0);
918
919 /// Return a new SourceLocation that encodes that the token starting
920 /// at \p TokenStart ends prematurely at \p TokenEnd.
921 SourceLocation createTokenSplitLoc(SourceLocation SpellingLoc,
922 SourceLocation TokenStart,
923 SourceLocation TokenEnd);
924
925 /// Retrieve the memory buffer associated with the given file.
926 ///
927 /// Returns None if the buffer is not valid.
928 llvm::Optional<llvm::MemoryBufferRef>
929 getMemoryBufferForFileOrNone(const FileEntry *File);
930
931 /// Retrieve the memory buffer associated with the given file.
932 ///
933 /// Returns a fake buffer if there isn't a real one.
934 llvm::MemoryBufferRef getMemoryBufferForFileOrFake(const FileEntry *File) {
935 if (auto B = getMemoryBufferForFileOrNone(File))
936 return *B;
937 return getFakeBufferForRecovery();
938 }
939
940 /// Override the contents of the given source file by providing an
941 /// already-allocated buffer.
942 ///
943 /// \param SourceFile the source file whose contents will be overridden.
944 ///
945 /// \param Buffer the memory buffer whose contents will be used as the
946 /// data in the given source file.
947 void overrideFileContents(const FileEntry *SourceFile,
948 const llvm::MemoryBufferRef &Buffer) {
949 overrideFileContents(SourceFile, llvm::MemoryBuffer::getMemBuffer(Buffer));
950 }
951
952 /// Override the contents of the given source file by providing an
953 /// already-allocated buffer.
954 ///
955 /// \param SourceFile the source file whose contents will be overridden.
956 ///
957 /// \param Buffer the memory buffer whose contents will be used as the
958 /// data in the given source file.
959 void overrideFileContents(const FileEntry *SourceFile,
960 std::unique_ptr<llvm::MemoryBuffer> Buffer);
961 void overrideFileContents(FileEntryRef SourceFile,
962 std::unique_ptr<llvm::MemoryBuffer> Buffer) {
963 overrideFileContents(&SourceFile.getFileEntry(), std::move(Buffer));
964 }
965
966 /// Override the given source file with another one.
967 ///
968 /// \param SourceFile the source file which will be overridden.
969 ///
970 /// \param NewFile the file whose contents will be used as the
971 /// data instead of the contents of the given source file.
972 void overrideFileContents(const FileEntry *SourceFile,
973 const FileEntry *NewFile);
974
975 /// Returns true if the file contents have been overridden.
976 bool isFileOverridden(const FileEntry *File) const {
977 if (OverriddenFilesInfo) {
978 if (OverriddenFilesInfo->OverriddenFilesWithBuffer.count(File))
979 return true;
980 if (OverriddenFilesInfo->OverriddenFiles.find(File) !=
981 OverriddenFilesInfo->OverriddenFiles.end())
982 return true;
983 }
984 return false;
985 }
986
987 /// Bypass the overridden contents of a file. This creates a new FileEntry
988 /// and initializes the content cache for it. Returns None if there is no
989 /// such file in the filesystem.
990 ///
991 /// This should be called before parsing has begun.
992 Optional<FileEntryRef> bypassFileContentsOverride(FileEntryRef File);
993
994 /// Specify that a file is transient.
995 void setFileIsTransient(const FileEntry *SourceFile);
996
997 /// Specify that all files that are read during this compilation are
998 /// transient.
999 void setAllFilesAreTransient(bool Transient) {
1000 FilesAreTransient = Transient;
1001 }
1002
1003 //===--------------------------------------------------------------------===//
1004 // FileID manipulation methods.
1005 //===--------------------------------------------------------------------===//
1006
1007 /// Return the buffer for the specified FileID.
1008 ///
1009 /// If there is an error opening this buffer the first time, return None.
1010 llvm::Optional<llvm::MemoryBufferRef>
1011 getBufferOrNone(FileID FID, SourceLocation Loc = SourceLocation()) const {
1012 if (auto *Entry = getSLocEntryForFile(FID))
1013 return Entry->getFile().getContentCache().getBufferOrNone(
1014 Diag, getFileManager(), Loc);
1015 return None;
1016 }
1017
1018 /// Return the buffer for the specified FileID.
1019 ///
1020 /// If there is an error opening this buffer the first time, this
1021 /// manufactures a temporary buffer and returns it.
1022 llvm::MemoryBufferRef
1023 getBufferOrFake(FileID FID, SourceLocation Loc = SourceLocation()) const {
1024 if (auto B = getBufferOrNone(FID, Loc))
1025 return *B;
1026 return getFakeBufferForRecovery();
1027 }
1028
1029 /// Returns the FileEntry record for the provided FileID.
1030 const FileEntry *getFileEntryForID(FileID FID) const {
1031 if (auto *Entry = getSLocEntryForFile(FID))
1032 return Entry->getFile().getContentCache().OrigEntry;
1033 return nullptr;
1034 }
1035
1036 /// Returns the FileEntryRef for the provided FileID.
1037 Optional<FileEntryRef> getFileEntryRefForID(FileID FID) const {
1038 if (auto *Entry
6.1
'Entry' is null
6.1
'Entry' is null
6.1
'Entry' is null
6.1
'Entry' is null
6.1
'Entry' is null
= getFileEntryForID(FID))
7
Taking false branch
1039 return Entry->getLastRef();
1040 return None;
8
Calling constructor for 'Optional<clang::FileEntryRef>'
16
Returning from constructor for 'Optional<clang::FileEntryRef>'
1041 }
1042
1043 /// Returns the filename for the provided FileID, unless it's a built-in
1044 /// buffer that's not represented by a filename.
1045 ///
1046 /// Returns None for non-files and built-in files.
1047 Optional<StringRef> getNonBuiltinFilenameForID(FileID FID) const;
1048
1049 /// Returns the FileEntry record for the provided SLocEntry.
1050 const FileEntry *getFileEntryForSLocEntry(const SrcMgr::SLocEntry &sloc) const
1051 {
1052 return sloc.getFile().getContentCache().OrigEntry;
1053 }
1054
1055 /// Return a StringRef to the source buffer data for the
1056 /// specified FileID.
1057 ///
1058 /// \param FID The file ID whose contents will be returned.
1059 /// \param Invalid If non-NULL, will be set true if an error occurred.
1060 StringRef getBufferData(FileID FID, bool *Invalid = nullptr) const;
1061
1062 /// Return a StringRef to the source buffer data for the
1063 /// specified FileID, returning None if invalid.
1064 ///
1065 /// \param FID The file ID whose contents will be returned.
1066 llvm::Optional<StringRef> getBufferDataOrNone(FileID FID) const;
1067
1068 /// Return a StringRef to the source buffer data for the
1069 /// specified FileID, returning None if it's not yet loaded.
1070 ///
1071 /// \param FID The file ID whose contents will be returned.
1072 llvm::Optional<StringRef> getBufferDataIfLoaded(FileID FID) const;
1073
1074 /// Get the number of FileIDs (files and macros) that were created
1075 /// during preprocessing of \p FID, including it.
1076 unsigned getNumCreatedFIDsForFileID(FileID FID) const {
1077 if (auto *Entry = getSLocEntryForFile(FID))
1078 return Entry->getFile().NumCreatedFIDs;
1079 return 0;
1080 }
1081
1082 /// Set the number of FileIDs (files and macros) that were created
1083 /// during preprocessing of \p FID, including it.
1084 void setNumCreatedFIDsForFileID(FileID FID, unsigned NumFIDs,
1085 bool Force = false) const {
1086 auto *Entry = getSLocEntryForFile(FID);
1087 if (!Entry)
1088 return;
1089 assert((Force || Entry->getFile().NumCreatedFIDs == 0) && "Already set!")(static_cast<void> (0));
1090 const_cast<SrcMgr::FileInfo &>(Entry->getFile()).NumCreatedFIDs = NumFIDs;
1091 }
1092
1093 //===--------------------------------------------------------------------===//
1094 // SourceLocation manipulation methods.
1095 //===--------------------------------------------------------------------===//
1096
1097 /// Return the FileID for a SourceLocation.
1098 ///
1099 /// This is a very hot method that is used for all SourceManager queries
1100 /// that start with a SourceLocation object. It is responsible for finding
1101 /// the entry in SLocEntryTable which contains the specified location.
1102 ///
1103 FileID getFileID(SourceLocation SpellingLoc) const {
1104 SourceLocation::UIntTy SLocOffset = SpellingLoc.getOffset();
1105
1106 // If our one-entry cache covers this offset, just return it.
1107 if (isOffsetInFileID(LastFileIDLookup, SLocOffset))
1108 return LastFileIDLookup;
1109
1110 return getFileIDSlow(SLocOffset);
1111 }
1112
1113 /// Return the filename of the file containing a SourceLocation.
1114 StringRef getFilename(SourceLocation SpellingLoc) const;
1115
1116 /// Return the source location corresponding to the first byte of
1117 /// the specified file.
1118 SourceLocation getLocForStartOfFile(FileID FID) const {
1119 if (auto *Entry = getSLocEntryForFile(FID))
1120 return SourceLocation::getFileLoc(Entry->getOffset());
1121 return SourceLocation();
1122 }
1123
1124 /// Return the source location corresponding to the last byte of the
1125 /// specified file.
1126 SourceLocation getLocForEndOfFile(FileID FID) const {
1127 if (auto *Entry = getSLocEntryForFile(FID))
1128 return SourceLocation::getFileLoc(Entry->getOffset() +
1129 getFileIDSize(FID));
1130 return SourceLocation();
1131 }
1132
1133 /// Returns the include location if \p FID is a \#include'd file
1134 /// otherwise it returns an invalid location.
1135 SourceLocation getIncludeLoc(FileID FID) const {
1136 if (auto *Entry = getSLocEntryForFile(FID))
1137 return Entry->getFile().getIncludeLoc();
1138 return SourceLocation();
1139 }
1140
1141 // Returns the import location if the given source location is
1142 // located within a module, or an invalid location if the source location
1143 // is within the current translation unit.
1144 std::pair<SourceLocation, StringRef>
1145 getModuleImportLoc(SourceLocation Loc) const {
1146 FileID FID = getFileID(Loc);
1147
1148 // Positive file IDs are in the current translation unit, and -1 is a
1149 // placeholder.
1150 if (FID.ID >= -1)
1151 return std::make_pair(SourceLocation(), "");
1152
1153 return ExternalSLocEntries->getModuleImportLoc(FID.ID);
1154 }
1155
1156 /// Given a SourceLocation object \p Loc, return the expansion
1157 /// location referenced by the ID.
1158 SourceLocation getExpansionLoc(SourceLocation Loc) const {
1159 // Handle the non-mapped case inline, defer to out of line code to handle
1160 // expansions.
1161 if (Loc.isFileID()) return Loc;
1162 return getExpansionLocSlowCase(Loc);
1163 }
1164
1165 /// Given \p Loc, if it is a macro location return the expansion
1166 /// location or the spelling location, depending on if it comes from a
1167 /// macro argument or not.
1168 SourceLocation getFileLoc(SourceLocation Loc) const {
1169 if (Loc.isFileID()) return Loc;
1170 return getFileLocSlowCase(Loc);
1171 }
1172
1173 /// Return the start/end of the expansion information for an
1174 /// expansion location.
1175 ///
1176 /// \pre \p Loc is required to be an expansion location.
1177 CharSourceRange getImmediateExpansionRange(SourceLocation Loc) const;
1178
1179 /// Given a SourceLocation object, return the range of
1180 /// tokens covered by the expansion in the ultimate file.
1181 CharSourceRange getExpansionRange(SourceLocation Loc) const;
1182
1183 /// Given a SourceRange object, return the range of
1184 /// tokens or characters covered by the expansion in the ultimate file.
1185 CharSourceRange getExpansionRange(SourceRange Range) const {
1186 SourceLocation Begin = getExpansionRange(Range.getBegin()).getBegin();
1187 CharSourceRange End = getExpansionRange(Range.getEnd());
1188 return CharSourceRange(SourceRange(Begin, End.getEnd()),
1189 End.isTokenRange());
1190 }
1191
1192 /// Given a CharSourceRange object, return the range of
1193 /// tokens or characters covered by the expansion in the ultimate file.
1194 CharSourceRange getExpansionRange(CharSourceRange Range) const {
1195 CharSourceRange Expansion = getExpansionRange(Range.getAsRange());
1196 if (Expansion.getEnd() == Range.getEnd())
1197 Expansion.setTokenRange(Range.isTokenRange());
1198 return Expansion;
1199 }
1200
1201 /// Given a SourceLocation object, return the spelling
1202 /// location referenced by the ID.
1203 ///
1204 /// This is the place where the characters that make up the lexed token
1205 /// can be found.
1206 SourceLocation getSpellingLoc(SourceLocation Loc) const {
1207 // Handle the non-mapped case inline, defer to out of line code to handle
1208 // expansions.
1209 if (Loc.isFileID()) return Loc;
1210 return getSpellingLocSlowCase(Loc);
1211 }
1212
1213 /// Given a SourceLocation object, return the spelling location
1214 /// referenced by the ID.
1215 ///
1216 /// This is the first level down towards the place where the characters
1217 /// that make up the lexed token can be found. This should not generally
1218 /// be used by clients.
1219 SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const;
1220
1221 /// Form a SourceLocation from a FileID and Offset pair.
1222 SourceLocation getComposedLoc(FileID FID, unsigned Offset) const {
1223 auto *Entry = getSLocEntryOrNull(FID);
1224 if (!Entry)
1225 return SourceLocation();
1226
1227 SourceLocation::UIntTy GlobalOffset = Entry->getOffset() + Offset;
1228 return Entry->isFile() ? SourceLocation::getFileLoc(GlobalOffset)
1229 : SourceLocation::getMacroLoc(GlobalOffset);
1230 }
1231
1232 /// Decompose the specified location into a raw FileID + Offset pair.
1233 ///
1234 /// The first element is the FileID, the second is the offset from the
1235 /// start of the buffer of the location.
1236 std::pair<FileID, unsigned> getDecomposedLoc(SourceLocation Loc) const {
1237 FileID FID = getFileID(Loc);
1238 auto *Entry = getSLocEntryOrNull(FID);
1239 if (!Entry)
1240 return std::make_pair(FileID(), 0);
1241 return std::make_pair(FID, Loc.getOffset() - Entry->getOffset());
1242 }
1243
1244 /// Decompose the specified location into a raw FileID + Offset pair.
1245 ///
1246 /// If the location is an expansion record, walk through it until we find
1247 /// the final location expanded.
1248 std::pair<FileID, unsigned>
1249 getDecomposedExpansionLoc(SourceLocation Loc) const {
1250 FileID FID = getFileID(Loc);
1251 auto *E = getSLocEntryOrNull(FID);
1252 if (!E)
1253 return std::make_pair(FileID(), 0);
1254
1255 unsigned Offset = Loc.getOffset()-E->getOffset();
1256 if (Loc.isFileID())
1257 return std::make_pair(FID, Offset);
1258
1259 return getDecomposedExpansionLocSlowCase(E);
1260 }
1261
1262 /// Decompose the specified location into a raw FileID + Offset pair.
1263 ///
1264 /// If the location is an expansion record, walk through it until we find
1265 /// its spelling record.
1266 std::pair<FileID, unsigned>
1267 getDecomposedSpellingLoc(SourceLocation Loc) const {
1268 FileID FID = getFileID(Loc);
1269 auto *E = getSLocEntryOrNull(FID);
1270 if (!E)
1271 return std::make_pair(FileID(), 0);
1272
1273 unsigned Offset = Loc.getOffset()-E->getOffset();
1274 if (Loc.isFileID())
1275 return std::make_pair(FID, Offset);
1276 return getDecomposedSpellingLocSlowCase(E, Offset);
1277 }
1278
1279 /// Returns the "included/expanded in" decomposed location of the given
1280 /// FileID.
1281 std::pair<FileID, unsigned> getDecomposedIncludedLoc(FileID FID) const;
1282
1283 /// Returns the offset from the start of the file that the
1284 /// specified SourceLocation represents.
1285 ///
1286 /// This is not very meaningful for a macro ID.
1287 unsigned getFileOffset(SourceLocation SpellingLoc) const {
1288 return getDecomposedLoc(SpellingLoc).second;
1289 }
1290
1291 /// Tests whether the given source location represents a macro
1292 /// argument's expansion into the function-like macro definition.
1293 ///
1294 /// \param StartLoc If non-null and function returns true, it is set to the
1295 /// start location of the macro argument expansion.
1296 ///
1297 /// Such source locations only appear inside of the expansion
1298 /// locations representing where a particular function-like macro was
1299 /// expanded.
1300 bool isMacroArgExpansion(SourceLocation Loc,
1301 SourceLocation *StartLoc = nullptr) const;
1302
1303 /// Tests whether the given source location represents the expansion of
1304 /// a macro body.
1305 ///
1306 /// This is equivalent to testing whether the location is part of a macro
1307 /// expansion but not the expansion of an argument to a function-like macro.
1308 bool isMacroBodyExpansion(SourceLocation Loc) const;
1309
1310 /// Returns true if the given MacroID location points at the beginning
1311 /// of the immediate macro expansion.
1312 ///
1313 /// \param MacroBegin If non-null and function returns true, it is set to the
1314 /// begin location of the immediate macro expansion.
1315 bool isAtStartOfImmediateMacroExpansion(SourceLocation Loc,
1316 SourceLocation *MacroBegin = nullptr) const;
1317
1318 /// Returns true if the given MacroID location points at the character
1319 /// end of the immediate macro expansion.
1320 ///
1321 /// \param MacroEnd If non-null and function returns true, it is set to the
1322 /// character end location of the immediate macro expansion.
1323 bool
1324 isAtEndOfImmediateMacroExpansion(SourceLocation Loc,
1325 SourceLocation *MacroEnd = nullptr) const;
1326
1327 /// Returns true if \p Loc is inside the [\p Start, +\p Length)
1328 /// chunk of the source location address space.
1329 ///
1330 /// If it's true and \p RelativeOffset is non-null, it will be set to the
1331 /// relative offset of \p Loc inside the chunk.
1332 bool
1333 isInSLocAddrSpace(SourceLocation Loc, SourceLocation Start, unsigned Length,
1334 SourceLocation::UIntTy *RelativeOffset = nullptr) const {
1335 assert(((Start.getOffset() < NextLocalOffset &&(static_cast<void> (0))
1336 Start.getOffset()+Length <= NextLocalOffset) ||(static_cast<void> (0))
1337 (Start.getOffset() >= CurrentLoadedOffset &&(static_cast<void> (0))
1338 Start.getOffset()+Length < MaxLoadedOffset)) &&(static_cast<void> (0))
1339 "Chunk is not valid SLoc address space")(static_cast<void> (0));
1340 SourceLocation::UIntTy LocOffs = Loc.getOffset();
1341 SourceLocation::UIntTy BeginOffs = Start.getOffset();
1342 SourceLocation::UIntTy EndOffs = BeginOffs + Length;
1343 if (LocOffs >= BeginOffs && LocOffs < EndOffs) {
1344 if (RelativeOffset)
1345 *RelativeOffset = LocOffs - BeginOffs;
1346 return true;
1347 }
1348
1349 return false;
1350 }
1351
1352 /// Return true if both \p LHS and \p RHS are in the local source
1353 /// location address space or the loaded one.
1354 ///
1355 /// If it's true and \p RelativeOffset is non-null, it will be set to the
1356 /// offset of \p RHS relative to \p LHS.
1357 bool isInSameSLocAddrSpace(SourceLocation LHS, SourceLocation RHS,
1358 SourceLocation::IntTy *RelativeOffset) const {
1359 SourceLocation::UIntTy LHSOffs = LHS.getOffset(), RHSOffs = RHS.getOffset();
1360 bool LHSLoaded = LHSOffs >= CurrentLoadedOffset;
1361 bool RHSLoaded = RHSOffs >= CurrentLoadedOffset;
1362
1363 if (LHSLoaded == RHSLoaded) {
1364 if (RelativeOffset)
1365 *RelativeOffset = RHSOffs - LHSOffs;
1366 return true;
1367 }
1368
1369 return false;
1370 }
1371
1372 //===--------------------------------------------------------------------===//
1373 // Queries about the code at a SourceLocation.
1374 //===--------------------------------------------------------------------===//
1375
1376 /// Return a pointer to the start of the specified location
1377 /// in the appropriate spelling MemoryBuffer.
1378 ///
1379 /// \param Invalid If non-NULL, will be set \c true if an error occurs.
1380 const char *getCharacterData(SourceLocation SL,
1381 bool *Invalid = nullptr) const;
1382
1383 /// Return the column # for the specified file position.
1384 ///
1385 /// This is significantly cheaper to compute than the line number. This
1386 /// returns zero if the column number isn't known. This may only be called
1387 /// on a file sloc, so you must choose a spelling or expansion location
1388 /// before calling this method.
1389 unsigned getColumnNumber(FileID FID, unsigned FilePos,
1390 bool *Invalid = nullptr) const;
1391 unsigned getSpellingColumnNumber(SourceLocation Loc,
1392 bool *Invalid = nullptr) const;
1393 unsigned getExpansionColumnNumber(SourceLocation Loc,
1394 bool *Invalid = nullptr) const;
1395 unsigned getPresumedColumnNumber(SourceLocation Loc,
1396 bool *Invalid = nullptr) const;
1397
1398 /// Given a SourceLocation, return the spelling line number
1399 /// for the position indicated.
1400 ///
1401 /// This requires building and caching a table of line offsets for the
1402 /// MemoryBuffer, so this is not cheap: use only when about to emit a
1403 /// diagnostic.
1404 unsigned getLineNumber(FileID FID, unsigned FilePos, bool *Invalid = nullptr) const;
1405 unsigned getSpellingLineNumber(SourceLocation Loc, bool *Invalid = nullptr) const;
1406 unsigned getExpansionLineNumber(SourceLocation Loc, bool *Invalid = nullptr) const;
1407 unsigned getPresumedLineNumber(SourceLocation Loc, bool *Invalid = nullptr) const;
1408
1409 /// Return the filename or buffer identifier of the buffer the
1410 /// location is in.
1411 ///
1412 /// Note that this name does not respect \#line directives. Use
1413 /// getPresumedLoc for normal clients.
1414 StringRef getBufferName(SourceLocation Loc, bool *Invalid = nullptr) const;
1415
1416 /// Return the file characteristic of the specified source
1417 /// location, indicating whether this is a normal file, a system
1418 /// header, or an "implicit extern C" system header.
1419 ///
1420 /// This state can be modified with flags on GNU linemarker directives like:
1421 /// \code
1422 /// # 4 "foo.h" 3
1423 /// \endcode
1424 /// which changes all source locations in the current file after that to be
1425 /// considered to be from a system header.
1426 SrcMgr::CharacteristicKind getFileCharacteristic(SourceLocation Loc) const;
1427
1428 /// Returns the "presumed" location of a SourceLocation specifies.
1429 ///
1430 /// A "presumed location" can be modified by \#line or GNU line marker
1431 /// directives. This provides a view on the data that a user should see
1432 /// in diagnostics, for example.
1433 ///
1434 /// Note that a presumed location is always given as the expansion point of
1435 /// an expansion location, not at the spelling location.
1436 ///
1437 /// \returns The presumed location of the specified SourceLocation. If the
1438 /// presumed location cannot be calculated (e.g., because \p Loc is invalid
1439 /// or the file containing \p Loc has changed on disk), returns an invalid
1440 /// presumed location.
1441 PresumedLoc getPresumedLoc(SourceLocation Loc,
1442 bool UseLineDirectives = true) const;
1443
1444 /// Returns whether the PresumedLoc for a given SourceLocation is
1445 /// in the main file.
1446 ///
1447 /// This computes the "presumed" location for a SourceLocation, then checks
1448 /// whether it came from a file other than the main file. This is different
1449 /// from isWrittenInMainFile() because it takes line marker directives into
1450 /// account.
1451 bool isInMainFile(SourceLocation Loc) const;
1452
1453 /// Returns true if the spelling locations for both SourceLocations
1454 /// are part of the same file buffer.
1455 ///
1456 /// This check ignores line marker directives.
1457 bool isWrittenInSameFile(SourceLocation Loc1, SourceLocation Loc2) const {
1458 return getFileID(Loc1) == getFileID(Loc2);
1459 }
1460
1461 /// Returns true if the spelling location for the given location
1462 /// is in the main file buffer.
1463 ///
1464 /// This check ignores line marker directives.
1465 bool isWrittenInMainFile(SourceLocation Loc) const {
1466 return getFileID(Loc) == getMainFileID();
1467 }
1468
1469 /// Returns whether \p Loc is located in a <built-in> file.
1470 bool isWrittenInBuiltinFile(SourceLocation Loc) const {
1471 StringRef Filename(getPresumedLoc(Loc).getFilename());
1472 return Filename.equals("<built-in>");
1473 }
1474
1475 /// Returns whether \p Loc is located in a <command line> file.
1476 bool isWrittenInCommandLineFile(SourceLocation Loc) const {
1477 StringRef Filename(getPresumedLoc(Loc).getFilename());
1478 return Filename.equals("<command line>");
1479 }
1480
1481 /// Returns whether \p Loc is located in a <scratch space> file.
1482 bool isWrittenInScratchSpace(SourceLocation Loc) const {
1483 StringRef Filename(getPresumedLoc(Loc).getFilename());
1484 return Filename.equals("<scratch space>");
1485 }
1486
1487 /// Returns if a SourceLocation is in a system header.
1488 bool isInSystemHeader(SourceLocation Loc) const {
1489 return isSystem(getFileCharacteristic(Loc));
1490 }
1491
1492 /// Returns if a SourceLocation is in an "extern C" system header.
1493 bool isInExternCSystemHeader(SourceLocation Loc) const {
1494 return getFileCharacteristic(Loc) == SrcMgr::C_ExternCSystem;
1495 }
1496
1497 /// Returns whether \p Loc is expanded from a macro in a system header.
1498 bool isInSystemMacro(SourceLocation loc) const {
1499 if (!loc.isMacroID())
1500 return false;
1501
1502 // This happens when the macro is the result of a paste, in that case
1503 // its spelling is the scratch memory, so we take the parent context.
1504 // There can be several level of token pasting.
1505 if (isWrittenInScratchSpace(getSpellingLoc(loc))) {
1506 do {
1507 loc = getImmediateMacroCallerLoc(loc);
1508 } while (isWrittenInScratchSpace(getSpellingLoc(loc)));
1509 return isInSystemMacro(loc);
1510 }
1511
1512 return isInSystemHeader(getSpellingLoc(loc));
1513 }
1514
1515 /// The size of the SLocEntry that \p FID represents.
1516 unsigned getFileIDSize(FileID FID) const;
1517
1518 /// Given a specific FileID, returns true if \p Loc is inside that
1519 /// FileID chunk and sets relative offset (offset of \p Loc from beginning
1520 /// of FileID) to \p relativeOffset.
1521 bool isInFileID(SourceLocation Loc, FileID FID,
1522 unsigned *RelativeOffset = nullptr) const {
1523 SourceLocation::UIntTy Offs = Loc.getOffset();
1524 if (isOffsetInFileID(FID, Offs)) {
1525 if (RelativeOffset)
1526 *RelativeOffset = Offs - getSLocEntry(FID).getOffset();
1527 return true;
1528 }
1529
1530 return false;
1531 }
1532
1533 //===--------------------------------------------------------------------===//
1534 // Line Table Manipulation Routines
1535 //===--------------------------------------------------------------------===//
1536
1537 /// Return the uniqued ID for the specified filename.
1538 unsigned getLineTableFilenameID(StringRef Str);
1539
1540 /// Add a line note to the line table for the FileID and offset
1541 /// specified by Loc.
1542 ///
1543 /// If FilenameID is -1, it is considered to be unspecified.
1544 void AddLineNote(SourceLocation Loc, unsigned LineNo, int FilenameID,
1545 bool IsFileEntry, bool IsFileExit,
1546 SrcMgr::CharacteristicKind FileKind);
1547
1548 /// Determine if the source manager has a line table.
1549 bool hasLineTable() const { return LineTable != nullptr; }
1550
1551 /// Retrieve the stored line table.
1552 LineTableInfo &getLineTable();
1553
1554 //===--------------------------------------------------------------------===//
1555 // Queries for performance analysis.
1556 //===--------------------------------------------------------------------===//
1557
1558 /// Return the total amount of physical memory allocated by the
1559 /// ContentCache allocator.
1560 size_t getContentCacheSize() const {
1561 return ContentCacheAlloc.getTotalMemory();
1562 }
1563
1564 struct MemoryBufferSizes {
1565 const size_t malloc_bytes;
1566 const size_t mmap_bytes;
1567
1568 MemoryBufferSizes(size_t malloc_bytes, size_t mmap_bytes)
1569 : malloc_bytes(malloc_bytes), mmap_bytes(mmap_bytes) {}
1570 };
1571
1572 /// Return the amount of memory used by memory buffers, breaking down
1573 /// by heap-backed versus mmap'ed memory.
1574 MemoryBufferSizes getMemoryBufferSizes() const;
1575
1576 /// Return the amount of memory used for various side tables and
1577 /// data structures in the SourceManager.
1578 size_t getDataStructureSizes() const;
1579
1580 //===--------------------------------------------------------------------===//
1581 // Other miscellaneous methods.
1582 //===--------------------------------------------------------------------===//
1583
1584 /// Get the source location for the given file:line:col triplet.
1585 ///
1586 /// If the source file is included multiple times, the source location will
1587 /// be based upon the first inclusion.
1588 SourceLocation translateFileLineCol(const FileEntry *SourceFile,
1589 unsigned Line, unsigned Col) const;
1590
1591 /// Get the FileID for the given file.
1592 ///
1593 /// If the source file is included multiple times, the FileID will be the
1594 /// first inclusion.
1595 FileID translateFile(const FileEntry *SourceFile) const;
1596 FileID translateFile(FileEntryRef SourceFile) const {
1597 return translateFile(&SourceFile.getFileEntry());
1598 }
1599
1600 /// Get the source location in \p FID for the given line:col.
1601 /// Returns null location if \p FID is not a file SLocEntry.
1602 SourceLocation translateLineCol(FileID FID,
1603 unsigned Line, unsigned Col) const;
1604
1605 /// If \p Loc points inside a function macro argument, the returned
1606 /// location will be the macro location in which the argument was expanded.
1607 /// If a macro argument is used multiple times, the expanded location will
1608 /// be at the first expansion of the argument.
1609 /// e.g.
1610 /// MY_MACRO(foo);
1611 /// ^
1612 /// Passing a file location pointing at 'foo', will yield a macro location
1613 /// where 'foo' was expanded into.
1614 SourceLocation getMacroArgExpandedLocation(SourceLocation Loc) const;
1615
1616 /// Determines the order of 2 source locations in the translation unit.
1617 ///
1618 /// \returns true if LHS source location comes before RHS, false otherwise.
1619 bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const;
1620
1621 /// Determines whether the two decomposed source location is in the
1622 /// same translation unit. As a byproduct, it also calculates the order
1623 /// of the source locations in case they are in the same TU.
1624 ///
1625 /// \returns Pair of bools the first component is true if the two locations
1626 /// are in the same TU. The second bool is true if the first is true
1627 /// and \p LOffs is before \p ROffs.
1628 std::pair<bool, bool>
1629 isInTheSameTranslationUnit(std::pair<FileID, unsigned> &LOffs,
1630 std::pair<FileID, unsigned> &ROffs) const;
1631
1632 /// Determines the order of 2 source locations in the "source location
1633 /// address space".
1634 bool isBeforeInSLocAddrSpace(SourceLocation LHS, SourceLocation RHS) const {
1635 return isBeforeInSLocAddrSpace(LHS, RHS.getOffset());
1636 }
1637
1638 /// Determines the order of a source location and a source location
1639 /// offset in the "source location address space".
1640 ///
1641 /// Note that we always consider source locations loaded from
1642 bool isBeforeInSLocAddrSpace(SourceLocation LHS,
1643 SourceLocation::UIntTy RHS) const {
1644 SourceLocation::UIntTy LHSOffset = LHS.getOffset();
1645 bool LHSLoaded = LHSOffset >= CurrentLoadedOffset;
1646 bool RHSLoaded = RHS >= CurrentLoadedOffset;
1647 if (LHSLoaded == RHSLoaded)
1648 return LHSOffset < RHS;
1649
1650 return LHSLoaded;
1651 }
1652
1653 /// Return true if the Point is within Start and End.
1654 bool isPointWithin(SourceLocation Location, SourceLocation Start,
1655 SourceLocation End) const {
1656 return Location == Start || Location == End ||
1657 (isBeforeInTranslationUnit(Start, Location) &&
1658 isBeforeInTranslationUnit(Location, End));
1659 }
1660
1661 // Iterators over FileInfos.
1662 using fileinfo_iterator =
1663 llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>::const_iterator;
1664
1665 fileinfo_iterator fileinfo_begin() const { return FileInfos.begin(); }
1666 fileinfo_iterator fileinfo_end() const { return FileInfos.end(); }
1667 bool hasFileInfo(const FileEntry *File) const {
1668 return FileInfos.find(File) != FileInfos.end();
1669 }
1670
1671 /// Print statistics to stderr.
1672 void PrintStats() const;
1673
1674 void dump() const;
1675
1676 /// Get the number of local SLocEntries we have.
1677 unsigned local_sloc_entry_size() const { return LocalSLocEntryTable.size(); }
1678
1679 /// Get a local SLocEntry. This is exposed for indexing.
1680 const SrcMgr::SLocEntry &getLocalSLocEntry(unsigned Index) const {
1681 assert(Index < LocalSLocEntryTable.size() && "Invalid index")(static_cast<void> (0));
1682 return LocalSLocEntryTable[Index];
1683 }
1684
1685 /// Get the number of loaded SLocEntries we have.
1686 unsigned loaded_sloc_entry_size() const { return LoadedSLocEntryTable.size();}
1687
1688 /// Get a loaded SLocEntry. This is exposed for indexing.
1689 const SrcMgr::SLocEntry &getLoadedSLocEntry(unsigned Index,
1690 bool *Invalid = nullptr) const {
1691 assert(Index < LoadedSLocEntryTable.size() && "Invalid index")(static_cast<void> (0));
1692 if (SLocEntryLoaded[Index])
1693 return LoadedSLocEntryTable[Index];
1694 return loadSLocEntry(Index, Invalid);
1695 }
1696
1697 const SrcMgr::SLocEntry &getSLocEntry(FileID FID,
1698 bool *Invalid = nullptr) const {
1699 if (FID.ID == 0 || FID.ID == -1) {
1700 if (Invalid) *Invalid = true;
1701 return LocalSLocEntryTable[0];
1702 }
1703 return getSLocEntryByID(FID.ID, Invalid);
1704 }
1705
1706 SourceLocation::UIntTy getNextLocalOffset() const { return NextLocalOffset; }
1707
1708 void setExternalSLocEntrySource(ExternalSLocEntrySource *Source) {
1709 assert(LoadedSLocEntryTable.empty() &&(static_cast<void> (0))
1710 "Invalidating existing loaded entries")(static_cast<void> (0));
1711 ExternalSLocEntries = Source;
1712 }
1713
1714 /// Allocate a number of loaded SLocEntries, which will be actually
1715 /// loaded on demand from the external source.
1716 ///
1717 /// NumSLocEntries will be allocated, which occupy a total of TotalSize space
1718 /// in the global source view. The lowest ID and the base offset of the
1719 /// entries will be returned.
1720 std::pair<int, SourceLocation::UIntTy>
1721 AllocateLoadedSLocEntries(unsigned NumSLocEntries,
1722 SourceLocation::UIntTy TotalSize);
1723
1724 /// Returns true if \p Loc came from a PCH/Module.
1725 bool isLoadedSourceLocation(SourceLocation Loc) const {
1726 return Loc.getOffset() >= CurrentLoadedOffset;
1727 }
1728
1729 /// Returns true if \p Loc did not come from a PCH/Module.
1730 bool isLocalSourceLocation(SourceLocation Loc) const {
1731 return Loc.getOffset() < NextLocalOffset;
1732 }
1733
1734 /// Returns true if \p FID came from a PCH/Module.
1735 bool isLoadedFileID(FileID FID) const {
1736 assert(FID.ID != -1 && "Using FileID sentinel value")(static_cast<void> (0));
1737 return FID.ID < 0;
1738 }
1739
1740 /// Returns true if \p FID did not come from a PCH/Module.
1741 bool isLocalFileID(FileID FID) const {
1742 return !isLoadedFileID(FID);
1743 }
1744
1745 /// Gets the location of the immediate macro caller, one level up the stack
1746 /// toward the initial macro typed into the source.
1747 SourceLocation getImmediateMacroCallerLoc(SourceLocation Loc) const {
1748 if (!Loc.isMacroID()) return Loc;
1749
1750 // When we have the location of (part of) an expanded parameter, its
1751 // spelling location points to the argument as expanded in the macro call,
1752 // and therefore is used to locate the macro caller.
1753 if (isMacroArgExpansion(Loc))
1754 return getImmediateSpellingLoc(Loc);
1755
1756 // Otherwise, the caller of the macro is located where this macro is
1757 // expanded (while the spelling is part of the macro definition).
1758 return getImmediateExpansionRange(Loc).getBegin();
1759 }
1760
1761 /// \return Location of the top-level macro caller.
1762 SourceLocation getTopMacroCallerLoc(SourceLocation Loc) const;
1763
1764private:
1765 friend class ASTReader;
1766 friend class ASTWriter;
1767
1768 llvm::MemoryBufferRef getFakeBufferForRecovery() const;
1769 SrcMgr::ContentCache &getFakeContentCacheForRecovery() const;
1770
1771 const SrcMgr::SLocEntry &loadSLocEntry(unsigned Index, bool *Invalid) const;
1772
1773 const SrcMgr::SLocEntry *getSLocEntryOrNull(FileID FID) const {
1774 bool Invalid = false;
1775 const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
1776 return Invalid ? nullptr : &Entry;
1777 }
1778
1779 const SrcMgr::SLocEntry *getSLocEntryForFile(FileID FID) const {
1780 if (auto *Entry = getSLocEntryOrNull(FID))
1781 if (Entry->isFile())
1782 return Entry;
1783 return nullptr;
1784 }
1785
1786 /// Get the entry with the given unwrapped FileID.
1787 /// Invalid will not be modified for Local IDs.
1788 const SrcMgr::SLocEntry &getSLocEntryByID(int ID,
1789 bool *Invalid = nullptr) const {
1790 assert(ID != -1 && "Using FileID sentinel value")(static_cast<void> (0));
1791 if (ID < 0)
1792 return getLoadedSLocEntryByID(ID, Invalid);
1793 return getLocalSLocEntry(static_cast<unsigned>(ID));
1794 }
1795
1796 const SrcMgr::SLocEntry &
1797 getLoadedSLocEntryByID(int ID, bool *Invalid = nullptr) const {
1798 return getLoadedSLocEntry(static_cast<unsigned>(-ID - 2), Invalid);
1799 }
1800
1801 /// Implements the common elements of storing an expansion info struct into
1802 /// the SLocEntry table and producing a source location that refers to it.
1803 SourceLocation
1804 createExpansionLocImpl(const SrcMgr::ExpansionInfo &Expansion,
1805 unsigned TokLength, int LoadedID = 0,
1806 SourceLocation::UIntTy LoadedOffset = 0);
1807
1808 /// Return true if the specified FileID contains the
1809 /// specified SourceLocation offset. This is a very hot method.
1810 inline bool isOffsetInFileID(FileID FID,
1811 SourceLocation::UIntTy SLocOffset) const {
1812 const SrcMgr::SLocEntry &Entry = getSLocEntry(FID);
1813 // If the entry is after the offset, it can't contain it.
1814 if (SLocOffset < Entry.getOffset()) return false;
1815
1816 // If this is the very last entry then it does.
1817 if (FID.ID == -2)
1818 return true;
1819
1820 // If it is the last local entry, then it does if the location is local.
1821 if (FID.ID+1 == static_cast<int>(LocalSLocEntryTable.size()))
1822 return SLocOffset < NextLocalOffset;
1823
1824 // Otherwise, the entry after it has to not include it. This works for both
1825 // local and loaded entries.
1826 return SLocOffset < getSLocEntryByID(FID.ID+1).getOffset();
1827 }
1828
1829 /// Returns the previous in-order FileID or an invalid FileID if there
1830 /// is no previous one.
1831 FileID getPreviousFileID(FileID FID) const;
1832
1833 /// Returns the next in-order FileID or an invalid FileID if there is
1834 /// no next one.
1835 FileID getNextFileID(FileID FID) const;
1836
1837 /// Create a new fileID for the specified ContentCache and
1838 /// include position.
1839 ///
1840 /// This works regardless of whether the ContentCache corresponds to a
1841 /// file or some other input source.
1842 FileID createFileIDImpl(SrcMgr::ContentCache &File, StringRef Filename,
1843 SourceLocation IncludePos,
1844 SrcMgr::CharacteristicKind DirCharacter, int LoadedID,
1845 SourceLocation::UIntTy LoadedOffset);
1846
1847 SrcMgr::ContentCache &getOrCreateContentCache(FileEntryRef SourceFile,
1848 bool isSystemFile = false);
1849
1850 /// Create a new ContentCache for the specified memory buffer.
1851 SrcMgr::ContentCache &
1852 createMemBufferContentCache(std::unique_ptr<llvm::MemoryBuffer> Buf);
1853
1854 FileID getFileIDSlow(SourceLocation::UIntTy SLocOffset) const;
1855 FileID getFileIDLocal(SourceLocation::UIntTy SLocOffset) const;
1856 FileID getFileIDLoaded(SourceLocation::UIntTy SLocOffset) const;
1857
1858 SourceLocation getExpansionLocSlowCase(SourceLocation Loc) const;
1859 SourceLocation getSpellingLocSlowCase(SourceLocation Loc) const;
1860 SourceLocation getFileLocSlowCase(SourceLocation Loc) const;
1861
1862 std::pair<FileID, unsigned>
1863 getDecomposedExpansionLocSlowCase(const SrcMgr::SLocEntry *E) const;
1864 std::pair<FileID, unsigned>
1865 getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E,
1866 unsigned Offset) const;
1867 void computeMacroArgsCache(MacroArgsMap &MacroArgsCache, FileID FID) const;
1868 void associateFileChunkWithMacroArgExp(MacroArgsMap &MacroArgsCache,
1869 FileID FID,
1870 SourceLocation SpellLoc,
1871 SourceLocation ExpansionLoc,
1872 unsigned ExpansionLength) const;
1873};
1874
1875/// Comparison function object.
1876template<typename T>
1877class BeforeThanCompare;
1878
1879/// Compare two source locations.
1880template<>
1881class BeforeThanCompare<SourceLocation> {
1882 SourceManager &SM;
1883
1884public:
1885 explicit BeforeThanCompare(SourceManager &SM) : SM(SM) {}
1886
1887 bool operator()(SourceLocation LHS, SourceLocation RHS) const {
1888 return SM.isBeforeInTranslationUnit(LHS, RHS);
1889 }
1890};
1891
1892/// Compare two non-overlapping source ranges.
1893template<>
1894class BeforeThanCompare<SourceRange> {
1895 SourceManager &SM;
1896
1897public:
1898 explicit BeforeThanCompare(SourceManager &SM) : SM(SM) {}
1899
1900 bool operator()(SourceRange LHS, SourceRange RHS) const {
1901 return SM.isBeforeInTranslationUnit(LHS.getBegin(), RHS.getBegin());
1902 }
1903};
1904
1905/// SourceManager and necessary depdencies (e.g. VFS, FileManager) for a single
1906/// in-memorty file.
1907class SourceManagerForFile {
1908public:
1909 /// Creates SourceManager and necessary depdencies (e.g. VFS, FileManager).
1910 /// The main file in the SourceManager will be \p FileName with \p Content.
1911 SourceManagerForFile(StringRef FileName, StringRef Content);
1912
1913 SourceManager &get() {
1914 assert(SourceMgr)(static_cast<void> (0));
1915 return *SourceMgr;
1916 }
1917
1918private:
1919 // The order of these fields are important - they should be in the same order
1920 // as they are created in `createSourceManagerForFile` so that they can be
1921 // deleted in the reverse order as they are created.
1922 std::unique_ptr<FileManager> FileMgr;
1923 std::unique_ptr<DiagnosticsEngine> Diagnostics;
1924 std::unique_ptr<SourceManager> SourceMgr;
1925};
1926
1927} // namespace clang
1928
1929#endif // LLVM_CLANG_BASIC_SOURCEMANAGER_H

/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/llvm/include/llvm/ADT/Optional.h

1//===- Optional.h - Simple variant for passing optional values --*- C++ -*-===//
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// This file provides Optional, a template class modeled in the spirit of
10// OCaml's 'opt' variant. The idea is to strongly type whether or not
11// a value can be optional.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_ADT_OPTIONAL_H
16#define LLVM_ADT_OPTIONAL_H
17
18#include "llvm/ADT/Hashing.h"
19#include "llvm/ADT/None.h"
20#include "llvm/ADT/STLForwardCompat.h"
21#include "llvm/Support/Compiler.h"
22#include "llvm/Support/type_traits.h"
23#include <cassert>
24#include <memory>
25#include <new>
26#include <utility>
27
28namespace llvm {
29
30class raw_ostream;
31
32namespace optional_detail {
33
34/// Storage for any type.
35//
36// The specialization condition intentionally uses
37// llvm::is_trivially_copy_constructible instead of
38// std::is_trivially_copy_constructible. GCC versions prior to 7.4 may
39// instantiate the copy constructor of `T` when
40// std::is_trivially_copy_constructible is instantiated. This causes
41// compilation to fail if we query the trivially copy constructible property of
42// a class which is not copy constructible.
43//
44// The current implementation of OptionalStorage insists that in order to use
45// the trivial specialization, the value_type must be trivially copy
46// constructible and trivially copy assignable due to =default implementations
47// of the copy/move constructor/assignment. It does not follow that this is
48// necessarily the case std::is_trivially_copyable is true (hence the expanded
49// specialization condition).
50//
51// The move constructible / assignable conditions emulate the remaining behavior
52// of std::is_trivially_copyable.
53template <typename T, bool = (llvm::is_trivially_copy_constructible<T>::value &&
54 std::is_trivially_copy_assignable<T>::value &&
55 (std::is_trivially_move_constructible<T>::value ||
56 !std::is_move_constructible<T>::value) &&
57 (std::is_trivially_move_assignable<T>::value ||
58 !std::is_move_assignable<T>::value))>
59class OptionalStorage {
60 union {
61 char empty;
62 T value;
63 };
64 bool hasVal;
65
66public:
67 ~OptionalStorage() { reset(); }
68
69 constexpr OptionalStorage() noexcept : empty(), hasVal(false) {}
70
71 constexpr OptionalStorage(OptionalStorage const &other) : OptionalStorage() {
72 if (other.hasValue()) {
73 emplace(other.value);
74 }
75 }
76 constexpr OptionalStorage(OptionalStorage &&other) : OptionalStorage() {
77 if (other.hasValue()) {
78 emplace(std::move(other.value));
79 }
80 }
81
82 template <class... Args>
83 constexpr explicit OptionalStorage(in_place_t, Args &&... args)
84 : value(std::forward<Args>(args)...), hasVal(true) {}
85
86 void reset() noexcept {
87 if (hasVal) {
88 value.~T();
89 hasVal = false;
90 }
91 }
92
93 constexpr bool hasValue() const noexcept { return hasVal; }
94
95 T &getValue() LLVM_LVALUE_FUNCTION& noexcept {
96 assert(hasVal)(static_cast<void> (0));
97 return value;
98 }
99 constexpr T const &getValue() const LLVM_LVALUE_FUNCTION& noexcept {
100 assert(hasVal)(static_cast<void> (0));
101 return value;
102 }
103#if LLVM_HAS_RVALUE_REFERENCE_THIS1
104 T &&getValue() && noexcept {
105 assert(hasVal)(static_cast<void> (0));
106 return std::move(value);
107 }
108#endif
109
110 template <class... Args> void emplace(Args &&... args) {
111 reset();
112 ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...);
113 hasVal = true;
114 }
115
116 OptionalStorage &operator=(T const &y) {
117 if (hasValue()) {
118 value = y;
119 } else {
120 ::new ((void *)std::addressof(value)) T(y);
121 hasVal = true;
122 }
123 return *this;
124 }
125 OptionalStorage &operator=(T &&y) {
126 if (hasValue()) {
127 value = std::move(y);
128 } else {
129 ::new ((void *)std::addressof(value)) T(std::move(y));
130 hasVal = true;
131 }
132 return *this;
133 }
134
135 OptionalStorage &operator=(OptionalStorage const &other) {
136 if (other.hasValue()) {
137 if (hasValue()) {
138 value = other.value;
139 } else {
140 ::new ((void *)std::addressof(value)) T(other.value);
141 hasVal = true;
142 }
143 } else {
144 reset();
145 }
146 return *this;
147 }
148
149 OptionalStorage &operator=(OptionalStorage &&other) {
150 if (other.hasValue()) {
151 if (hasValue()) {
152 value = std::move(other.value);
153 } else {
154 ::new ((void *)std::addressof(value)) T(std::move(other.value));
155 hasVal = true;
156 }
157 } else {
158 reset();
159 }
160 return *this;
161 }
162};
163
164template <typename T> class OptionalStorage<T, true> {
165 union {
166 char empty;
167 T value;
168 };
169 bool hasVal = false;
170
171public:
172 ~OptionalStorage() = default;
173
174 constexpr OptionalStorage() noexcept : empty{} {}
175
176 constexpr OptionalStorage(OptionalStorage const &other) = default;
177 constexpr OptionalStorage(OptionalStorage &&other) = default;
178
179 OptionalStorage &operator=(OptionalStorage const &other) = default;
180 OptionalStorage &operator=(OptionalStorage &&other) = default;
181
182 template <class... Args>
183 constexpr explicit OptionalStorage(in_place_t, Args &&... args)
184 : value(std::forward<Args>(args)...), hasVal(true) {}
185
186 void reset() noexcept {
187 if (hasVal) {
188 value.~T();
189 hasVal = false;
190 }
191 }
192
193 constexpr bool hasValue() const noexcept { return hasVal; }
194
195 T &getValue() LLVM_LVALUE_FUNCTION& noexcept {
196 assert(hasVal)(static_cast<void> (0));
197 return value;
198 }
199 constexpr T const &getValue() const LLVM_LVALUE_FUNCTION& noexcept {
200 assert(hasVal)(static_cast<void> (0));
201 return value;
202 }
203#if LLVM_HAS_RVALUE_REFERENCE_THIS1
204 T &&getValue() && noexcept {
205 assert(hasVal)(static_cast<void> (0));
206 return std::move(value);
207 }
208#endif
209
210 template <class... Args> void emplace(Args &&... args) {
211 reset();
212 ::new ((void *)std::addressof(value)) T(std::forward<Args>(args)...);
213 hasVal = true;
214 }
215
216 OptionalStorage &operator=(T const &y) {
217 if (hasValue()) {
218 value = y;
219 } else {
220 ::new ((void *)std::addressof(value)) T(y);
221 hasVal = true;
222 }
223 return *this;
224 }
225 OptionalStorage &operator=(T &&y) {
226 if (hasValue()) {
227 value = std::move(y);
228 } else {
229 ::new ((void *)std::addressof(value)) T(std::move(y));
230 hasVal = true;
231 }
232 return *this;
233 }
234};
235
236} // namespace optional_detail
237
238template <typename T> class Optional {
239 optional_detail::OptionalStorage<T> Storage;
240
241public:
242 using value_type = T;
243
244 constexpr Optional() {}
245 constexpr Optional(NoneType) {}
9
Calling defaulted default constructor for 'OptionalStorage<clang::FileEntryRef, true>'
15
Returning from default constructor for 'OptionalStorage<clang::FileEntryRef, true>'
246
247 constexpr Optional(const T &y) : Storage(in_place, y) {}
248 constexpr Optional(const Optional &O) = default;
249
250 constexpr Optional(T &&y) : Storage(in_place, std::move(y)) {}
251 constexpr Optional(Optional &&O) = default;
252
253 template <typename... ArgTypes>
254 constexpr Optional(in_place_t, ArgTypes &&...Args)
255 : Storage(in_place, std::forward<ArgTypes>(Args)...) {}
256
257 Optional &operator=(T &&y) {
258 Storage = std::move(y);
259 return *this;
260 }
261 Optional &operator=(Optional &&O) = default;
262
263 /// Create a new object by constructing it in place with the given arguments.
264 template <typename... ArgTypes> void emplace(ArgTypes &&... Args) {
265 Storage.emplace(std::forward<ArgTypes>(Args)...);
266 }
267
268 static constexpr Optional create(const T *y) {
269 return y ? Optional(*y) : Optional();
270 }
271
272 Optional &operator=(const T &y) {
273 Storage = y;
274 return *this;
275 }
276 Optional &operator=(const Optional &O) = default;
277
278 void reset() { Storage.reset(); }
279
280 constexpr const T *getPointer() const { return &Storage.getValue(); }
281 T *getPointer() { return &Storage.getValue(); }
282 constexpr const T &getValue() const LLVM_LVALUE_FUNCTION& {
283 return Storage.getValue();
284 }
285 T &getValue() LLVM_LVALUE_FUNCTION& { return Storage.getValue(); }
286
287 constexpr explicit operator bool() const { return hasValue(); }
288 constexpr bool hasValue() const { return Storage.hasValue(); }
289 constexpr const T *operator->() const { return getPointer(); }
290 T *operator->() { return getPointer(); }
291 constexpr const T &operator*() const LLVM_LVALUE_FUNCTION& {
292 return getValue();
293 }
294 T &operator*() LLVM_LVALUE_FUNCTION& { return getValue(); }
295
296 template <typename U>
297 constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION& {
298 return hasValue() ? getValue() : std::forward<U>(value);
299 }
300
301 /// Apply a function to the value if present; otherwise return None.
302 template <class Function>
303 auto map(const Function &F) const LLVM_LVALUE_FUNCTION&
304 -> Optional<decltype(F(getValue()))> {
305 if (*this) return F(getValue());
306 return None;
307 }
308
309#if LLVM_HAS_RVALUE_REFERENCE_THIS1
310 T &&getValue() && { return std::move(Storage.getValue()); }
311 T &&operator*() && { return std::move(Storage.getValue()); }
312
313 template <typename U>
314 T getValueOr(U &&value) && {
315 return hasValue() ? std::move(getValue()) : std::forward<U>(value);
316 }
317
318 /// Apply a function to the value if present; otherwise return None.
319 template <class Function>
320 auto map(const Function &F) &&
321 -> Optional<decltype(F(std::move(*this).getValue()))> {
322 if (*this) return F(std::move(*this).getValue());
323 return None;
324 }
325#endif
326};
327
328template <class T> llvm::hash_code hash_value(const Optional<T> &O) {
329 return O ? hash_combine(true, *O) : hash_value(false);
330}
331
332template <typename T, typename U>
333constexpr bool operator==(const Optional<T> &X, const Optional<U> &Y) {
334 if (X && Y)
335 return *X == *Y;
336 return X.hasValue() == Y.hasValue();
337}
338
339template <typename T, typename U>
340constexpr bool operator!=(const Optional<T> &X, const Optional<U> &Y) {
341 return !(X == Y);
342}
343
344template <typename T, typename U>
345constexpr bool operator<(const Optional<T> &X, const Optional<U> &Y) {
346 if (X && Y)
347 return *X < *Y;
348 return X.hasValue() < Y.hasValue();
349}
350
351template <typename T, typename U>
352constexpr bool operator<=(const Optional<T> &X, const Optional<U> &Y) {
353 return !(Y < X);
354}
355
356template <typename T, typename U>
357constexpr bool operator>(const Optional<T> &X, const Optional<U> &Y) {
358 return Y < X;
359}
360
361template <typename T, typename U>
362constexpr bool operator>=(const Optional<T> &X, const Optional<U> &Y) {
363 return !(X < Y);
364}
365
366template <typename T>
367constexpr bool operator==(const Optional<T> &X, NoneType) {
368 return !X;
369}
370
371template <typename T>
372constexpr bool operator==(NoneType, const Optional<T> &X) {
373 return X == None;
374}
375
376template <typename T>
377constexpr bool operator!=(const Optional<T> &X, NoneType) {
378 return !(X == None);
379}
380
381template <typename T>
382constexpr bool operator!=(NoneType, const Optional<T> &X) {
383 return X != None;
384}
385
386template <typename T> constexpr bool operator<(const Optional<T> &, NoneType) {
387 return false;
388}
389
390template <typename T> constexpr bool operator<(NoneType, const Optional<T> &X) {
391 return X.hasValue();
392}
393
394template <typename T>
395constexpr bool operator<=(const Optional<T> &X, NoneType) {
396 return !(None < X);
397}
398
399template <typename T>
400constexpr bool operator<=(NoneType, const Optional<T> &X) {
401 return !(X < None);
402}
403
404template <typename T> constexpr bool operator>(const Optional<T> &X, NoneType) {
405 return None < X;
406}
407
408template <typename T> constexpr bool operator>(NoneType, const Optional<T> &X) {
409 return X < None;
410}
411
412template <typename T>
413constexpr bool operator>=(const Optional<T> &X, NoneType) {
414 return None <= X;
415}
416
417template <typename T>
418constexpr bool operator>=(NoneType, const Optional<T> &X) {
419 return X <= None;
420}
421
422template <typename T>
423constexpr bool operator==(const Optional<T> &X, const T &Y) {
424 return X && *X == Y;
425}
426
427template <typename T>
428constexpr bool operator==(const T &X, const Optional<T> &Y) {
429 return Y && X == *Y;
430}
431
432template <typename T>
433constexpr bool operator!=(const Optional<T> &X, const T &Y) {
434 return !(X == Y);
435}
436
437template <typename T>
438constexpr bool operator!=(const T &X, const Optional<T> &Y) {
439 return !(X == Y);
440}
441
442template <typename T>
443constexpr bool operator<(const Optional<T> &X, const T &Y) {
444 return !X || *X < Y;
445}
446
447template <typename T>
448constexpr bool operator<(const T &X, const Optional<T> &Y) {
449 return Y && X < *Y;
450}
451
452template <typename T>
453constexpr bool operator<=(const Optional<T> &X, const T &Y) {
454 return !(Y < X);
455}
456
457template <typename T>
458constexpr bool operator<=(const T &X, const Optional<T> &Y) {
459 return !(Y < X);
460}
461
462template <typename T>
463constexpr bool operator>(const Optional<T> &X, const T &Y) {
464 return Y < X;
465}
466
467template <typename T>
468constexpr bool operator>(const T &X, const Optional<T> &Y) {
469 return Y < X;
470}
471
472template <typename T>
473constexpr bool operator>=(const Optional<T> &X, const T &Y) {
474 return !(X < Y);
475}
476
477template <typename T>
478constexpr bool operator>=(const T &X, const Optional<T> &Y) {
479 return !(X < Y);
480}
481
482raw_ostream &operator<<(raw_ostream &OS, NoneType);
483
484template <typename T, typename = decltype(std::declval<raw_ostream &>()
485 << std::declval<const T &>())>
486raw_ostream &operator<<(raw_ostream &OS, const Optional<T> &O) {
487 if (O)
488 OS << *O;
489 else
490 OS << None;
491 return OS;
492}
493
494} // end namespace llvm
495
496#endif // LLVM_ADT_OPTIONAL_H

/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/clang/include/clang/Basic/FileEntry.h

1//===- clang/Basic/FileEntry.h - File references ----------------*- C++ -*-===//
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/// \file
10/// Defines interfaces for clang::FileEntry and clang::FileEntryRef.
11///
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_BASIC_FILEENTRY_H
15#define LLVM_CLANG_BASIC_FILEENTRY_H
16
17#include "clang/Basic/DirectoryEntry.h"
18#include "clang/Basic/LLVM.h"
19#include "llvm/ADT/DenseMapInfo.h"
20#include "llvm/ADT/Hashing.h"
21#include "llvm/ADT/PointerUnion.h"
22#include "llvm/ADT/StringMap.h"
23#include "llvm/ADT/StringRef.h"
24#include "llvm/Support/ErrorOr.h"
25#include "llvm/Support/FileSystem/UniqueID.h"
26
27namespace llvm {
28
29class MemoryBuffer;
30
31namespace vfs {
32
33class File;
34
35} // namespace vfs
36} // namespace llvm
37
38namespace clang {
39
40class FileEntryRef;
41
42} // namespace clang
43
44namespace llvm {
45namespace optional_detail {
46
47/// Forward declare a template specialization for OptionalStorage.
48template <>
49class OptionalStorage<clang::FileEntryRef, /*is_trivially_copyable*/ true>;
50
51} // namespace optional_detail
52} // namespace llvm
53
54namespace clang {
55
56class FileEntry;
57
58/// A reference to a \c FileEntry that includes the name of the file as it was
59/// accessed by the FileManager's client.
60class FileEntryRef {
61public:
62 StringRef getName() const { return ME->first(); }
19
Called C++ object pointer is null
63 const FileEntry &getFileEntry() const {
64 return *ME->second->V.get<FileEntry *>();
65 }
66 DirectoryEntryRef getDir() const { return *ME->second->Dir; }
67
68 inline bool isValid() const;
69 inline off_t getSize() const;
70 inline unsigned getUID() const;
71 inline const llvm::sys::fs::UniqueID &getUniqueID() const;
72 inline time_t getModificationTime() const;
73 inline bool isNamedPipe() const;
74 inline void closeFile() const;
75
76 /// Check if the underlying FileEntry is the same, intentially ignoring
77 /// whether the file was referenced with the same spelling of the filename.
78 friend bool operator==(const FileEntryRef &LHS, const FileEntryRef &RHS) {
79 return &LHS.getFileEntry() == &RHS.getFileEntry();
80 }
81 friend bool operator==(const FileEntry *LHS, const FileEntryRef &RHS) {
82 return LHS == &RHS.getFileEntry();
83 }
84 friend bool operator==(const FileEntryRef &LHS, const FileEntry *RHS) {
85 return &LHS.getFileEntry() == RHS;
86 }
87 friend bool operator!=(const FileEntryRef &LHS, const FileEntryRef &RHS) {
88 return !(LHS == RHS);
89 }
90 friend bool operator!=(const FileEntry *LHS, const FileEntryRef &RHS) {
91 return !(LHS == RHS);
92 }
93 friend bool operator!=(const FileEntryRef &LHS, const FileEntry *RHS) {
94 return !(LHS == RHS);
95 }
96
97 /// Hash code is based on the FileEntry, not the specific named reference,
98 /// just like operator==.
99 friend llvm::hash_code hash_value(FileEntryRef Ref) {
100 return llvm::hash_value(&Ref.getFileEntry());
101 }
102
103 struct MapValue;
104
105 /// Type used in the StringMap.
106 using MapEntry = llvm::StringMapEntry<llvm::ErrorOr<MapValue>>;
107
108 /// Type stored in the StringMap.
109 struct MapValue {
110 /// The pointer at another MapEntry is used when the FileManager should
111 /// silently forward from one name to another, which occurs in Redirecting
112 /// VFSs that use external names. In that case, the \c FileEntryRef
113 /// returned by the \c FileManager will have the external name, and not the
114 /// name that was used to lookup the file.
115 ///
116 /// The second type is really a `const MapEntry *`, but that confuses
117 /// gcc5.3. Once that's no longer supported, change this back.
118 llvm::PointerUnion<FileEntry *, const void *> V;
119
120 /// Directory the file was found in. Set if and only if V is a FileEntry.
121 Optional<DirectoryEntryRef> Dir;
122
123 MapValue() = delete;
124 MapValue(FileEntry &FE, DirectoryEntryRef Dir) : V(&FE), Dir(Dir) {}
125 MapValue(MapEntry &ME) : V(&ME) {}
126 };
127
128 /// Check if RHS referenced the file in exactly the same way.
129 bool isSameRef(const FileEntryRef &RHS) const { return ME == RHS.ME; }
130
131 /// Allow FileEntryRef to degrade into 'const FileEntry*' to facilitate
132 /// incremental adoption.
133 ///
134 /// The goal is to avoid code churn due to dances like the following:
135 /// \code
136 /// // Old code.
137 /// lvalue = rvalue;
138 ///
139 /// // Temporary code from an incremental patch.
140 /// lvalue = &rvalue.getFileEntry();
141 ///
142 /// // Final code.
143 /// lvalue = rvalue;
144 /// \endcode
145 ///
146 /// FIXME: Once FileEntryRef is "everywhere" and FileEntry::LastRef and
147 /// FileEntry::getName have been deleted, delete this implicit conversion.
148 operator const FileEntry *() const { return &getFileEntry(); }
149
150 FileEntryRef() = delete;
151 explicit FileEntryRef(const MapEntry &ME) : ME(&ME) {
152 assert(ME.second && "Expected payload")(static_cast<void> (0));
153 assert(ME.second->V && "Expected non-null")(static_cast<void> (0));
154 assert(ME.second->V.is<FileEntry *>() && "Expected FileEntry")(static_cast<void> (0));
155 }
156
157 /// Expose the underlying MapEntry to simplify packing in a PointerIntPair or
158 /// PointerUnion and allow construction in Optional.
159 const clang::FileEntryRef::MapEntry &getMapEntry() const { return *ME; }
160
161private:
162 friend class FileMgr::MapEntryOptionalStorage<FileEntryRef>;
163 struct optional_none_tag {};
164
165 // Private constructor for use by OptionalStorage.
166 FileEntryRef(optional_none_tag) : ME(nullptr) {}
12
Null pointer value stored to 'file.Storage.MaybeRef.ME'
167 bool hasOptionalValue() const { return ME; }
168
169 friend struct llvm::DenseMapInfo<FileEntryRef>;
170 struct dense_map_empty_tag {};
171 struct dense_map_tombstone_tag {};
172
173 // Private constructors for use by DenseMapInfo.
174 FileEntryRef(dense_map_empty_tag)
175 : ME(llvm::DenseMapInfo<const MapEntry *>::getEmptyKey()) {}
176 FileEntryRef(dense_map_tombstone_tag)
177 : ME(llvm::DenseMapInfo<const MapEntry *>::getTombstoneKey()) {}
178 bool isSpecialDenseMapKey() const {
179 return isSameRef(FileEntryRef(dense_map_empty_tag())) ||
180 isSameRef(FileEntryRef(dense_map_tombstone_tag()));
181 }
182
183 const MapEntry *ME;
184};
185
186static_assert(sizeof(FileEntryRef) == sizeof(const FileEntry *),
187 "FileEntryRef must avoid size overhead");
188
189static_assert(std::is_trivially_copyable<FileEntryRef>::value,
190 "FileEntryRef must be trivially copyable");
191
192} // end namespace clang
193
194namespace llvm {
195namespace optional_detail {
196
197/// Customize OptionalStorage<FileEntryRef> to use FileEntryRef and its
198/// optional_none_tag to keep it the size of a single pointer.
199template <>
200class OptionalStorage<clang::FileEntryRef>
201 : public clang::FileMgr::MapEntryOptionalStorage<clang::FileEntryRef> {
202 using StorageImpl =
203 clang::FileMgr::MapEntryOptionalStorage<clang::FileEntryRef>;
204
205public:
206 OptionalStorage() = default;
10
Calling default constructor for 'MapEntryOptionalStorage<clang::FileEntryRef>'
14
Returning from default constructor for 'MapEntryOptionalStorage<clang::FileEntryRef>'
207
208 template <class... ArgTypes>
209 explicit OptionalStorage(in_place_t, ArgTypes &&...Args)
210 : StorageImpl(in_place_t{}, std::forward<ArgTypes>(Args)...) {}
211
212 OptionalStorage &operator=(clang::FileEntryRef Ref) {
213 StorageImpl::operator=(Ref);
214 return *this;
215 }
216};
217
218static_assert(sizeof(Optional<clang::FileEntryRef>) ==
219 sizeof(clang::FileEntryRef),
220 "Optional<FileEntryRef> must avoid size overhead");
221
222static_assert(std::is_trivially_copyable<Optional<clang::FileEntryRef>>::value,
223 "Optional<FileEntryRef> should be trivially copyable");
224
225} // end namespace optional_detail
226
227/// Specialisation of DenseMapInfo for FileEntryRef.
228template <> struct DenseMapInfo<clang::FileEntryRef> {
229 static inline clang::FileEntryRef getEmptyKey() {
230 return clang::FileEntryRef(clang::FileEntryRef::dense_map_empty_tag());
231 }
232
233 static inline clang::FileEntryRef getTombstoneKey() {
234 return clang::FileEntryRef(clang::FileEntryRef::dense_map_tombstone_tag());
235 }
236
237 static unsigned getHashValue(clang::FileEntryRef Val) {
238 return hash_value(Val);
239 }
240
241 static bool isEqual(clang::FileEntryRef LHS, clang::FileEntryRef RHS) {
242 // Catch the easy cases: both empty, both tombstone, or the same ref.
243 if (LHS.isSameRef(RHS))
244 return true;
245
246 // Confirm LHS and RHS are valid.
247 if (LHS.isSpecialDenseMapKey() || RHS.isSpecialDenseMapKey())
248 return false;
249
250 // It's safe to use operator==.
251 return LHS == RHS;
252 }
253};
254
255} // end namespace llvm
256
257namespace clang {
258
259/// Wrapper around Optional<FileEntryRef> that degrades to 'const FileEntry*',
260/// facilitating incremental patches to propagate FileEntryRef.
261///
262/// This class can be used as return value or field where it's convenient for
263/// an Optional<FileEntryRef> to degrade to a 'const FileEntry*'. The purpose
264/// is to avoid code churn due to dances like the following:
265/// \code
266/// // Old code.
267/// lvalue = rvalue;
268///
269/// // Temporary code from an incremental patch.
270/// Optional<FileEntryRef> MaybeF = rvalue;
271/// lvalue = MaybeF ? &MaybeF.getFileEntry() : nullptr;
272///
273/// // Final code.
274/// lvalue = rvalue;
275/// \endcode
276///
277/// FIXME: Once FileEntryRef is "everywhere" and FileEntry::LastRef and
278/// FileEntry::getName have been deleted, delete this class and replace
279/// instances with Optional<FileEntryRef>.
280class OptionalFileEntryRefDegradesToFileEntryPtr
281 : public Optional<FileEntryRef> {
282public:
283 OptionalFileEntryRefDegradesToFileEntryPtr() = default;
284 OptionalFileEntryRefDegradesToFileEntryPtr(
285 OptionalFileEntryRefDegradesToFileEntryPtr &&) = default;
286 OptionalFileEntryRefDegradesToFileEntryPtr(
287 const OptionalFileEntryRefDegradesToFileEntryPtr &) = default;
288 OptionalFileEntryRefDegradesToFileEntryPtr &
289 operator=(OptionalFileEntryRefDegradesToFileEntryPtr &&) = default;
290 OptionalFileEntryRefDegradesToFileEntryPtr &
291 operator=(const OptionalFileEntryRefDegradesToFileEntryPtr &) = default;
292
293 OptionalFileEntryRefDegradesToFileEntryPtr(llvm::NoneType) {}
294 OptionalFileEntryRefDegradesToFileEntryPtr(FileEntryRef Ref)
295 : Optional<FileEntryRef>(Ref) {}
296 OptionalFileEntryRefDegradesToFileEntryPtr(Optional<FileEntryRef> MaybeRef)
297 : Optional<FileEntryRef>(MaybeRef) {}
298
299 OptionalFileEntryRefDegradesToFileEntryPtr &operator=(llvm::NoneType) {
300 Optional<FileEntryRef>::operator=(None);
301 return *this;
302 }
303 OptionalFileEntryRefDegradesToFileEntryPtr &operator=(FileEntryRef Ref) {
304 Optional<FileEntryRef>::operator=(Ref);
305 return *this;
306 }
307 OptionalFileEntryRefDegradesToFileEntryPtr &
308 operator=(Optional<FileEntryRef> MaybeRef) {
309 Optional<FileEntryRef>::operator=(MaybeRef);
310 return *this;
311 }
312
313 /// Degrade to 'const FileEntry *' to allow FileEntry::LastRef and
314 /// FileEntry::getName have been deleted, delete this class and replace
315 /// instances with Optional<FileEntryRef>
316 operator const FileEntry *() const {
317 return hasValue() ? &getValue().getFileEntry() : nullptr;
318 }
319};
320
321static_assert(
322 std::is_trivially_copyable<
323 OptionalFileEntryRefDegradesToFileEntryPtr>::value,
324 "OptionalFileEntryRefDegradesToFileEntryPtr should be trivially copyable");
325
326/// Cached information about one file (either on disk
327/// or in the virtual file system).
328///
329/// If the 'File' member is valid, then this FileEntry has an open file
330/// descriptor for the file.
331class FileEntry {
332 friend class FileManager;
333
334 std::string RealPathName; // Real path to the file; could be empty.
335 off_t Size = 0; // File size in bytes.
336 time_t ModTime = 0; // Modification time of file.
337 const DirectoryEntry *Dir = nullptr; // Directory file lives in.
338 llvm::sys::fs::UniqueID UniqueID;
339 unsigned UID = 0; // A unique (small) ID for the file.
340 bool IsNamedPipe = false;
341 bool IsValid = false; // Is this \c FileEntry initialized and valid?
342
343 /// The open file, if it is owned by the \p FileEntry.
344 mutable std::unique_ptr<llvm::vfs::File> File;
345
346 /// The file content, if it is owned by the \p FileEntry.
347 std::unique_ptr<llvm::MemoryBuffer> Content;
348
349 // First access name for this FileEntry.
350 //
351 // This is Optional only to allow delayed construction (FileEntryRef has no
352 // default constructor). It should always have a value in practice.
353 //
354 // TODO: remove this once everyone that needs a name uses FileEntryRef.
355 Optional<FileEntryRef> LastRef;
356
357public:
358 FileEntry();
359 ~FileEntry();
360
361 FileEntry(const FileEntry &) = delete;
362 FileEntry &operator=(const FileEntry &) = delete;
363
364 StringRef getName() const { return LastRef->getName(); }
365 FileEntryRef getLastRef() const { return *LastRef; }
366
367 StringRef tryGetRealPathName() const { return RealPathName; }
368 bool isValid() const { return IsValid; }
369 off_t getSize() const { return Size; }
370 unsigned getUID() const { return UID; }
371 const llvm::sys::fs::UniqueID &getUniqueID() const { return UniqueID; }
372 time_t getModificationTime() const { return ModTime; }
373
374 /// Return the directory the file lives in.
375 const DirectoryEntry *getDir() const { return Dir; }
376
377 bool operator<(const FileEntry &RHS) const { return UniqueID < RHS.UniqueID; }
378
379 /// Check whether the file is a named pipe (and thus can't be opened by
380 /// the native FileManager methods).
381 bool isNamedPipe() const { return IsNamedPipe; }
382
383 void closeFile() const;
384};
385
386bool FileEntryRef::isValid() const { return getFileEntry().isValid(); }
387
388off_t FileEntryRef::getSize() const { return getFileEntry().getSize(); }
389
390unsigned FileEntryRef::getUID() const { return getFileEntry().getUID(); }
391
392const llvm::sys::fs::UniqueID &FileEntryRef::getUniqueID() const {
393 return getFileEntry().getUniqueID();
394}
395
396time_t FileEntryRef::getModificationTime() const {
397 return getFileEntry().getModificationTime();
398}
399
400bool FileEntryRef::isNamedPipe() const { return getFileEntry().isNamedPipe(); }
401
402void FileEntryRef::closeFile() const { getFileEntry().closeFile(); }
403
404} // end namespace clang
405
406#endif // LLVM_CLANG_BASIC_FILEENTRY_H

/build/llvm-toolchain-snapshot-14~++20210903100615+fd66b44ec19e/clang/include/clang/Basic/DirectoryEntry.h

1//===- clang/Basic/DirectoryEntry.h - Directory references ------*- C++ -*-===//
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/// \file
10/// Defines interfaces for clang::DirectoryEntry and clang::DirectoryEntryRef.
11///
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_BASIC_DIRECTORYENTRY_H
15#define LLVM_CLANG_BASIC_DIRECTORYENTRY_H
16
17#include "clang/Basic/LLVM.h"
18#include "llvm/ADT/DenseMapInfo.h"
19#include "llvm/ADT/Hashing.h"
20#include "llvm/ADT/StringMap.h"
21#include "llvm/ADT/StringRef.h"
22#include "llvm/Support/ErrorOr.h"
23
24namespace clang {
25namespace FileMgr {
26
27template <class RefTy> class MapEntryOptionalStorage;
28
29} // end namespace FileMgr
30
31/// Cached information about one directory (either on disk or in
32/// the virtual file system).
33class DirectoryEntry {
34 friend class FileManager;
35
36 // FIXME: We should not be storing a directory entry name here.
37 StringRef Name; // Name of the directory.
38
39public:
40 StringRef getName() const { return Name; }
41};
42
43/// A reference to a \c DirectoryEntry that includes the name of the directory
44/// as it was accessed by the FileManager's client.
45class DirectoryEntryRef {
46public:
47 const DirectoryEntry &getDirEntry() const { return *ME->getValue(); }
48
49 StringRef getName() const { return ME->getKey(); }
50
51 /// Hash code is based on the DirectoryEntry, not the specific named
52 /// reference.
53 friend llvm::hash_code hash_value(DirectoryEntryRef Ref) {
54 return llvm::hash_value(&Ref.getDirEntry());
55 }
56
57 using MapEntry = llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>>;
58
59 const MapEntry &getMapEntry() const { return *ME; }
60
61 /// Check if RHS referenced the file in exactly the same way.
62 bool isSameRef(DirectoryEntryRef RHS) const { return ME == RHS.ME; }
63
64 DirectoryEntryRef() = delete;
65 DirectoryEntryRef(const MapEntry &ME) : ME(&ME) {}
66
67 /// Allow DirectoryEntryRef to degrade into 'const DirectoryEntry*' to
68 /// facilitate incremental adoption.
69 ///
70 /// The goal is to avoid code churn due to dances like the following:
71 /// \code
72 /// // Old code.
73 /// lvalue = rvalue;
74 ///
75 /// // Temporary code from an incremental patch.
76 /// lvalue = &rvalue.getDirectoryEntry();
77 ///
78 /// // Final code.
79 /// lvalue = rvalue;
80 /// \endcode
81 ///
82 /// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::getName
83 /// has been deleted, delete this implicit conversion.
84 operator const DirectoryEntry *() const { return &getDirEntry(); }
85
86private:
87 friend class FileMgr::MapEntryOptionalStorage<DirectoryEntryRef>;
88 struct optional_none_tag {};
89
90 // Private constructor for use by OptionalStorage.
91 DirectoryEntryRef(optional_none_tag) : ME(nullptr) {}
92 bool hasOptionalValue() const { return ME; }
93
94 friend struct llvm::DenseMapInfo<DirectoryEntryRef>;
95 struct dense_map_empty_tag {};
96 struct dense_map_tombstone_tag {};
97
98 // Private constructors for use by DenseMapInfo.
99 DirectoryEntryRef(dense_map_empty_tag)
100 : ME(llvm::DenseMapInfo<const MapEntry *>::getEmptyKey()) {}
101 DirectoryEntryRef(dense_map_tombstone_tag)
102 : ME(llvm::DenseMapInfo<const MapEntry *>::getTombstoneKey()) {}
103 bool isSpecialDenseMapKey() const {
104 return isSameRef(DirectoryEntryRef(dense_map_empty_tag())) ||
105 isSameRef(DirectoryEntryRef(dense_map_tombstone_tag()));
106 }
107
108 const MapEntry *ME;
109};
110
111namespace FileMgr {
112
113/// Customized storage for refs derived from map entires in FileManager, using
114/// the private optional_none_tag to keep it to the size of a single pointer.
115template <class RefTy> class MapEntryOptionalStorage {
116 using optional_none_tag = typename RefTy::optional_none_tag;
117 RefTy MaybeRef;
118
119public:
120 MapEntryOptionalStorage() : MaybeRef(optional_none_tag()) {}
11
Calling constructor for 'FileEntryRef'
13
Returning from constructor for 'FileEntryRef'
121
122 template <class... ArgTypes>
123 explicit MapEntryOptionalStorage(llvm::in_place_t, ArgTypes &&...Args)
124 : MaybeRef(std::forward<ArgTypes>(Args)...) {}
125
126 void reset() { MaybeRef = optional_none_tag(); }
127
128 bool hasValue() const { return MaybeRef.hasOptionalValue(); }
129
130 RefTy &getValue() LLVM_LVALUE_FUNCTION& {
131 assert(hasValue())(static_cast<void> (0));
132 return MaybeRef;
133 }
134 RefTy const &getValue() const LLVM_LVALUE_FUNCTION& {
135 assert(hasValue())(static_cast<void> (0));
136 return MaybeRef;
137 }
138#if LLVM_HAS_RVALUE_REFERENCE_THIS1
139 RefTy &&getValue() && {
140 assert(hasValue())(static_cast<void> (0));
141 return std::move(MaybeRef);
142 }
143#endif
144
145 template <class... Args> void emplace(Args &&...args) {
146 MaybeRef = RefTy(std::forward<Args>(args)...);
147 }
148
149 MapEntryOptionalStorage &operator=(RefTy Ref) {
150 MaybeRef = Ref;
151 return *this;
152 }
153};
154
155} // end namespace FileMgr
156} // end namespace clang
157
158namespace llvm {
159namespace optional_detail {
160
161/// Customize OptionalStorage<DirectoryEntryRef> to use DirectoryEntryRef and
162/// its optional_none_tag to keep it the size of a single pointer.
163template <>
164class OptionalStorage<clang::DirectoryEntryRef>
165 : public clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef> {
166 using StorageImpl =
167 clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef>;
168
169public:
170 OptionalStorage() = default;
171
172 template <class... ArgTypes>
173 explicit OptionalStorage(in_place_t, ArgTypes &&...Args)
174 : StorageImpl(in_place_t{}, std::forward<ArgTypes>(Args)...) {}
175
176 OptionalStorage &operator=(clang::DirectoryEntryRef Ref) {
177 StorageImpl::operator=(Ref);
178 return *this;
179 }
180};
181
182static_assert(sizeof(Optional<clang::DirectoryEntryRef>) ==
183 sizeof(clang::DirectoryEntryRef),
184 "Optional<DirectoryEntryRef> must avoid size overhead");
185
186static_assert(
187 std::is_trivially_copyable<Optional<clang::DirectoryEntryRef>>::value,
188 "Optional<DirectoryEntryRef> should be trivially copyable");
189
190} // end namespace optional_detail
191
192/// Specialisation of DenseMapInfo for DirectoryEntryRef.
193template <> struct DenseMapInfo<clang::DirectoryEntryRef> {
194 static inline clang::DirectoryEntryRef getEmptyKey() {
195 return clang::DirectoryEntryRef(
196 clang::DirectoryEntryRef::dense_map_empty_tag());
197 }
198
199 static inline clang::DirectoryEntryRef getTombstoneKey() {
200 return clang::DirectoryEntryRef(
201 clang::DirectoryEntryRef::dense_map_tombstone_tag());
202 }
203
204 static unsigned getHashValue(clang::DirectoryEntryRef Val) {
205 return hash_value(Val);
206 }
207
208 static bool isEqual(clang::DirectoryEntryRef LHS,
209 clang::DirectoryEntryRef RHS) {
210 // Catch the easy cases: both empty, both tombstone, or the same ref.
211 if (LHS.isSameRef(RHS))
212 return true;
213
214 // Confirm LHS and RHS are valid.
215 if (LHS.isSpecialDenseMapKey() || RHS.isSpecialDenseMapKey())
216 return false;
217
218 // It's safe to use operator==.
219 return LHS == RHS;
220 }
221};
222
223} // end namespace llvm
224
225namespace clang {
226
227/// Wrapper around Optional<DirectoryEntryRef> that degrades to 'const
228/// DirectoryEntry*', facilitating incremental patches to propagate
229/// DirectoryEntryRef.
230///
231/// This class can be used as return value or field where it's convenient for
232/// an Optional<DirectoryEntryRef> to degrade to a 'const DirectoryEntry*'. The
233/// purpose is to avoid code churn due to dances like the following:
234/// \code
235/// // Old code.
236/// lvalue = rvalue;
237///
238/// // Temporary code from an incremental patch.
239/// Optional<DirectoryEntryRef> MaybeF = rvalue;
240/// lvalue = MaybeF ? &MaybeF.getDirectoryEntry() : nullptr;
241///
242/// // Final code.
243/// lvalue = rvalue;
244/// \endcode
245///
246/// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::LastRef
247/// and DirectoryEntry::getName have been deleted, delete this class and
248/// replace instances with Optional<DirectoryEntryRef>.
249class OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr
250 : public Optional<DirectoryEntryRef> {
251public:
252 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr() = default;
253 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(
254 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default;
255 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(
256 const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default;
257 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
258 operator=(OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default;
259 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
260 operator=(const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default;
261
262 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(llvm::NoneType) {}
263 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(DirectoryEntryRef Ref)
264 : Optional<DirectoryEntryRef>(Ref) {}
265 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(Optional<DirectoryEntryRef> MaybeRef)
266 : Optional<DirectoryEntryRef>(MaybeRef) {}
267
268 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &operator=(llvm::NoneType) {
269 Optional<DirectoryEntryRef>::operator=(None);
270 return *this;
271 }
272 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &operator=(DirectoryEntryRef Ref) {
273 Optional<DirectoryEntryRef>::operator=(Ref);
274 return *this;
275 }
276 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
277 operator=(Optional<DirectoryEntryRef> MaybeRef) {
278 Optional<DirectoryEntryRef>::operator=(MaybeRef);
279 return *this;
280 }
281
282 /// Degrade to 'const DirectoryEntry *' to allow DirectoryEntry::LastRef and
283 /// DirectoryEntry::getName have been deleted, delete this class and replace
284 /// instances with Optional<DirectoryEntryRef>
285 operator const DirectoryEntry *() const {
286 return hasValue() ? &getValue().getDirEntry() : nullptr;
287 }
288};
289
290static_assert(std::is_trivially_copyable<
291 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr>::value,
292 "OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr should be "
293 "trivially copyable");
294
295} // end namespace clang
296
297#endif // LLVM_CLANG_BASIC_DIRECTORYENTRY_H