1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "clang/AST/AST.h"
7 #include "clang/AST/ASTConsumer.h"
8 #include "clang/AST/ASTContext.h"
9 #include "clang/AST/Expr.h"
10 #include "clang/AST/ExprCXX.h"
11 #include "clang/AST/Mangle.h"
12 #include "clang/AST/RecursiveASTVisitor.h"
13 #include "clang/Basic/SourceManager.h"
14 #include "clang/Basic/Version.h"
15 #include "clang/Frontend/CompilerInstance.h"
16 #include "clang/Frontend/FrontendPluginRegistry.h"
17 #include "clang/Lex/Lexer.h"
18 #include "clang/Lex/PPCallbacks.h"
19 #include "clang/Lex/Preprocessor.h"
20 #include "llvm/ADT/SmallString.h"
21 #include "llvm/Support/raw_ostream.h"
22 
23 #include <iostream>
24 #include <map>
25 #include <memory>
26 #include <sstream>
27 #include <tuple>
28 #include <unordered_set>
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 
33 #include "FileOperations.h"
34 #include "JSONFormatter.h"
35 #include "StringOperations.h"
36 
37 using namespace clang;
38 
39 const std::string GENERATED("__GENERATED__" PATHSEP_STRING);
40 
41 // Absolute path to directory containing source code.
42 std::string Srcdir;
43 
44 // Absolute path to objdir (including generated code).
45 std::string Objdir;
46 
47 // Absolute path where analysis JSON output will be stored.
48 std::string Outdir;
49 
50 #if !defined(_WIN32) && !defined(_WIN64)
51 #include <sys/time.h>
52 
time()53 static double time() {
54   struct timeval Tv;
55   gettimeofday(&Tv, nullptr);
56   return double(Tv.tv_sec) + double(Tv.tv_usec) / 1000000.;
57 }
58 #endif
59 
60 // Return true if |input| is a valid C++ identifier. We don't want to generate
61 // analysis information for operators, string literals, etc. by accident since
62 // it trips up consumers of the data.
isValidIdentifier(std::string Input)63 static bool isValidIdentifier(std::string Input) {
64   for (char C : Input) {
65     if (!(isalpha(C) || isdigit(C) || C == '_')) {
66       return false;
67     }
68   }
69   return true;
70 }
71 
72 struct RAIITracer {
RAIITracerRAIITracer73   RAIITracer(const char *log) : mLog(log) {
74     printf("<%s>\n", mLog);
75   }
76 
~RAIITracerRAIITracer77   ~RAIITracer() {
78     printf("</%s>\n", mLog);
79   }
80 
81   const char* mLog;
82 };
83 
84 #define TRACEFUNC RAIITracer tracer(__FUNCTION__);
85 
86 class IndexConsumer;
87 
88 // For each C++ file seen by the analysis (.cpp or .h), we track a
89 // FileInfo. This object tracks whether the file is "interesting" (i.e., whether
90 // it's in the source dir or the objdir). We also store the analysis output
91 // here.
92 struct FileInfo {
FileInfoFileInfo93   FileInfo(std::string &Rname) : Realname(Rname) {
94     if (Rname.compare(0, Objdir.length(), Objdir) == 0) {
95       // We're in the objdir, so we are probably a generated header
96       // We use the escape character to indicate the objdir nature.
97       // Note that output also has the `/' already placed
98       Interesting = true;
99       Realname.replace(0, Objdir.length(), GENERATED);
100       return;
101     }
102 
103     // Empty filenames can get turned into Srcdir when they are resolved as
104     // absolute paths, so we should exclude files that are exactly equal to
105     // Srcdir or anything outside Srcdir.
106     Interesting = (Rname.length() > Srcdir.length()) &&
107                   (Rname.compare(0, Srcdir.length(), Srcdir) == 0);
108     if (Interesting) {
109       // Remove the trailing `/' as well.
110       Realname.erase(0, Srcdir.length() + 1);
111     }
112   }
113   std::string Realname;
114   std::vector<std::string> Output;
115   bool Interesting;
116 };
117 
118 class IndexConsumer;
119 
120 class PreprocessorHook : public PPCallbacks {
121   IndexConsumer *Indexer;
122 
123 public:
PreprocessorHook(IndexConsumer * C)124   PreprocessorHook(IndexConsumer *C) : Indexer(C) {}
125 
126   virtual void MacroDefined(const Token &Tok,
127                             const MacroDirective *Md) override;
128 
129   virtual void MacroExpands(const Token &Tok, const MacroDefinition &Md,
130                             SourceRange Range, const MacroArgs *Ma) override;
131 #if CLANG_VERSION_MAJOR >= 5
132   virtual void MacroUndefined(const Token &Tok, const MacroDefinition &Md,
133                               const MacroDirective *Undef) override;
134 #else
135   virtual void MacroUndefined(const Token &Tok,
136                               const MacroDefinition &Md) override;
137 #endif
138   virtual void Defined(const Token &Tok, const MacroDefinition &Md,
139                        SourceRange Range) override;
140   virtual void Ifdef(SourceLocation Loc, const Token &Tok,
141                      const MacroDefinition &Md) override;
142   virtual void Ifndef(SourceLocation Loc, const Token &Tok,
143                       const MacroDefinition &Md) override;
144 };
145 
146 class IndexConsumer : public ASTConsumer,
147                       public RecursiveASTVisitor<IndexConsumer>,
148                       public DiagnosticConsumer {
149 private:
150   CompilerInstance &CI;
151   SourceManager &SM;
152   std::map<FileID, std::unique_ptr<FileInfo>> FileMap;
153   MangleContext *CurMangleContext;
154   ASTContext *AstContext;
155 
156   typedef RecursiveASTVisitor<IndexConsumer> Super;
157 
158   // Tracks the set of declarations that the current expression/statement is
159   // nested inside of.
160   struct AutoSetContext {
AutoSetContextIndexConsumer::AutoSetContext161     AutoSetContext(IndexConsumer *Self, NamedDecl *Context)
162         : Self(Self), Prev(Self->CurDeclContext), Decl(Context) {
163       Self->CurDeclContext = this;
164     }
165 
~AutoSetContextIndexConsumer::AutoSetContext166     ~AutoSetContext() { Self->CurDeclContext = Prev; }
167 
168     IndexConsumer *Self;
169     AutoSetContext *Prev;
170     NamedDecl *Decl;
171   };
172   AutoSetContext *CurDeclContext;
173 
getFileInfo(SourceLocation Loc)174   FileInfo *getFileInfo(SourceLocation Loc) {
175     FileID Id = SM.getFileID(Loc);
176 
177     std::map<FileID, std::unique_ptr<FileInfo>>::iterator It;
178     It = FileMap.find(Id);
179     if (It == FileMap.end()) {
180       // We haven't seen this file before. We need to make the FileInfo
181       // structure information ourselves
182       std::string Filename = SM.getFilename(Loc);
183       std::string Absolute;
184       // If Loc is a macro id rather than a file id, it Filename might be
185       // empty. Also for some types of file locations that are clang-internal
186       // like "<scratch>" it can return an empty Filename. In these cases we
187       // want to leave Absolute as empty.
188       if (!Filename.empty()) {
189         Absolute = getAbsolutePath(Filename);
190         if (Absolute.empty()) {
191           Absolute = Filename;
192         }
193       }
194       std::unique_ptr<FileInfo> Info = llvm::make_unique<FileInfo>(Absolute);
195       It = FileMap.insert(std::make_pair(Id, std::move(Info))).first;
196     }
197     return It->second.get();
198   }
199 
200   // Helpers for processing declarations
201   // Should we ignore this location?
isInterestingLocation(SourceLocation Loc)202   bool isInterestingLocation(SourceLocation Loc) {
203     if (Loc.isInvalid()) {
204       return false;
205     }
206 
207     return getFileInfo(Loc)->Interesting;
208   }
209 
locationToString(SourceLocation Loc,size_t Length=0)210   std::string locationToString(SourceLocation Loc, size_t Length = 0) {
211     std::pair<FileID, unsigned> Pair = SM.getDecomposedLoc(Loc);
212 
213     bool IsInvalid;
214     unsigned Line = SM.getLineNumber(Pair.first, Pair.second, &IsInvalid);
215     if (IsInvalid) {
216       return "";
217     }
218     unsigned Column = SM.getColumnNumber(Pair.first, Pair.second, &IsInvalid);
219     if (IsInvalid) {
220       return "";
221     }
222 
223     if (Length) {
224       return stringFormat("%05d:%d-%d", Line, Column - 1, Column - 1 + Length);
225     } else {
226       return stringFormat("%05d:%d", Line, Column - 1);
227     }
228   }
229 
lineRangeToString(SourceRange Range)230   std::string lineRangeToString(SourceRange Range) {
231     std::pair<FileID, unsigned> Begin = SM.getDecomposedLoc(Range.getBegin());
232     std::pair<FileID, unsigned> End = SM.getDecomposedLoc(Range.getEnd());
233 
234     bool IsInvalid;
235     unsigned Line1 = SM.getLineNumber(Begin.first, Begin.second, &IsInvalid);
236     if (IsInvalid) {
237       return "";
238     }
239     unsigned Line2 = SM.getLineNumber(End.first, End.second, &IsInvalid);
240     if (IsInvalid) {
241       return "";
242     }
243 
244     return stringFormat("%d-%d", Line1, Line2);
245   }
246 
247   // Returns the qualified name of `d` without considering template parameters.
getQualifiedName(const NamedDecl * D)248   std::string getQualifiedName(const NamedDecl *D) {
249     const DeclContext *Ctx = D->getDeclContext();
250     if (Ctx->isFunctionOrMethod()) {
251       return D->getQualifiedNameAsString();
252     }
253 
254     std::vector<const DeclContext *> Contexts;
255 
256     // Collect contexts.
257     while (Ctx && isa<NamedDecl>(Ctx)) {
258       Contexts.push_back(Ctx);
259       Ctx = Ctx->getParent();
260     }
261 
262     std::string Result;
263 
264     std::reverse(Contexts.begin(), Contexts.end());
265 
266     for (const DeclContext *DC : Contexts) {
267       if (const auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(DC)) {
268         Result += Spec->getNameAsString();
269 
270         if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization) {
271           std::string Backing;
272           llvm::raw_string_ostream Stream(Backing);
273           const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs();
274 #if CLANG_VERSION_MAJOR > 3 ||                                                 \
275     (CLANG_VERSION_MAJOR == 3 && CLANG_VERSION_MINOR >= 9)
276           TemplateSpecializationType::PrintTemplateArgumentList(
277               Stream, TemplateArgs.asArray(), PrintingPolicy(CI.getLangOpts()));
278 #else
279           TemplateSpecializationType::PrintTemplateArgumentList(
280               stream, templateArgs.data(), templateArgs.size(),
281               PrintingPolicy(CI.getLangOpts()));
282 #endif
283           Result += Stream.str();
284         }
285       } else if (const auto *Nd = dyn_cast<NamespaceDecl>(DC)) {
286         if (Nd->isAnonymousNamespace() || Nd->isInline()) {
287           continue;
288         }
289         Result += Nd->getNameAsString();
290       } else if (const auto *Rd = dyn_cast<RecordDecl>(DC)) {
291         if (!Rd->getIdentifier()) {
292           Result += "(anonymous)";
293         } else {
294           Result += Rd->getNameAsString();
295         }
296       } else if (const auto *Fd = dyn_cast<FunctionDecl>(DC)) {
297         Result += Fd->getNameAsString();
298       } else if (const auto *Ed = dyn_cast<EnumDecl>(DC)) {
299         // C++ [dcl.enum]p10: Each enum-name and each unscoped
300         // enumerator is declared in the scope that immediately contains
301         // the enum-specifier. Each scoped enumerator is declared in the
302         // scope of the enumeration.
303         if (Ed->isScoped() || Ed->getIdentifier())
304           Result += Ed->getNameAsString();
305         else
306           continue;
307       } else {
308         Result += cast<NamedDecl>(DC)->getNameAsString();
309       }
310       Result += "::";
311     }
312 
313     if (D->getDeclName())
314       Result += D->getNameAsString();
315     else
316       Result += "(anonymous)";
317 
318     return Result;
319   }
320 
mangleLocation(SourceLocation Loc,std::string Backup=std::string ())321   std::string mangleLocation(SourceLocation Loc,
322                              std::string Backup = std::string()) {
323     FileInfo *F = getFileInfo(Loc);
324     std::string Filename = F->Realname;
325     if (Filename.length() == 0 && Backup.length() != 0) {
326       return Backup;
327     }
328     return hash(Filename + std::string("@") + locationToString(Loc));
329   }
330 
mangleQualifiedName(std::string Name)331   std::string mangleQualifiedName(std::string Name) {
332     std::replace(Name.begin(), Name.end(), ' ', '_');
333     return Name;
334   }
335 
getMangledName(clang::MangleContext * Ctx,const clang::NamedDecl * Decl)336   std::string getMangledName(clang::MangleContext *Ctx,
337                              const clang::NamedDecl *Decl) {
338     if (isa<FunctionDecl>(Decl) && cast<FunctionDecl>(Decl)->isExternC()) {
339       return cast<FunctionDecl>(Decl)->getNameAsString();
340     }
341 
342     if (isa<FunctionDecl>(Decl) || isa<VarDecl>(Decl)) {
343       const DeclContext *DC = Decl->getDeclContext();
344       if (isa<TranslationUnitDecl>(DC) || isa<NamespaceDecl>(DC) ||
345           isa<LinkageSpecDecl>(DC) ||
346           // isa<ExternCContextDecl>(DC) ||
347           isa<TagDecl>(DC)) {
348         llvm::SmallVector<char, 512> Output;
349         llvm::raw_svector_ostream Out(Output);
350         if (const CXXConstructorDecl *D = dyn_cast<CXXConstructorDecl>(Decl)) {
351           Ctx->mangleCXXCtor(D, CXXCtorType::Ctor_Complete, Out);
352         } else if (const CXXDestructorDecl *D =
353                        dyn_cast<CXXDestructorDecl>(Decl)) {
354           Ctx->mangleCXXDtor(D, CXXDtorType::Dtor_Complete, Out);
355         } else {
356           Ctx->mangleName(Decl, Out);
357         }
358         return Out.str().str();
359       } else {
360         return std::string("V_") + mangleLocation(Decl->getLocation()) +
361                std::string("_") + hash(Decl->getName());
362       }
363     } else if (isa<TagDecl>(Decl) || isa<TypedefNameDecl>(Decl)) {
364       if (!Decl->getIdentifier()) {
365         // Anonymous.
366         return std::string("T_") + mangleLocation(Decl->getLocation());
367       }
368 
369       return std::string("T_") + mangleQualifiedName(getQualifiedName(Decl));
370     } else if (isa<NamespaceDecl>(Decl) || isa<NamespaceAliasDecl>(Decl)) {
371       if (!Decl->getIdentifier()) {
372         // Anonymous.
373         return std::string("NS_") + mangleLocation(Decl->getLocation());
374       }
375 
376       return std::string("NS_") + mangleQualifiedName(getQualifiedName(Decl));
377     } else if (const FieldDecl *D2 = dyn_cast<FieldDecl>(Decl)) {
378       const RecordDecl *Record = D2->getParent();
379       return std::string("F_<") + getMangledName(Ctx, Record) + ">_" +
380              toString(D2->getFieldIndex());
381     } else if (const EnumConstantDecl *D2 = dyn_cast<EnumConstantDecl>(Decl)) {
382       const DeclContext *DC = Decl->getDeclContext();
383       if (const NamedDecl *Named = dyn_cast<NamedDecl>(DC)) {
384         return std::string("E_<") + getMangledName(Ctx, Named) + ">_" +
385                D2->getNameAsString();
386       }
387     }
388 
389     assert(false);
390     return std::string("");
391   }
392 
debugLocation(SourceLocation Loc)393   void debugLocation(SourceLocation Loc) {
394     std::string S = locationToString(Loc);
395     StringRef Filename = SM.getFilename(Loc);
396     printf("--> %s %s\n", std::string(Filename).c_str(), S.c_str());
397   }
398 
debugRange(SourceRange Range)399   void debugRange(SourceRange Range) {
400     printf("Range\n");
401     debugLocation(Range.getBegin());
402     debugLocation(Range.getEnd());
403   }
404 
405 public:
IndexConsumer(CompilerInstance & CI)406   IndexConsumer(CompilerInstance &CI)
407       : CI(CI), SM(CI.getSourceManager()), CurMangleContext(nullptr),
408         AstContext(nullptr), CurDeclContext(nullptr), TemplateStack(nullptr) {
409     CI.getPreprocessor().addPPCallbacks(
410         llvm::make_unique<PreprocessorHook>(this));
411   }
412 
clone(DiagnosticsEngine & Diags) const413   virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
414     return new IndexConsumer(CI);
415   }
416 
417 #if !defined(_WIN32) && !defined(_WIN64)
418   struct AutoTime {
AutoTimeIndexConsumer::AutoTime419     AutoTime(double *Counter) : Counter(Counter), Start(time()) {}
~AutoTimeIndexConsumer::AutoTime420     ~AutoTime() {
421       if (Start) {
422         *Counter += time() - Start;
423       }
424     }
stopIndexConsumer::AutoTime425     void stop() {
426       *Counter += time() - Start;
427       Start = 0;
428     }
429     double *Counter;
430     double Start;
431   };
432 #endif
433 
434   // All we need is to follow the final declaration.
HandleTranslationUnit(ASTContext & Ctx)435   virtual void HandleTranslationUnit(ASTContext &Ctx) {
436     CurMangleContext =
437       clang::ItaniumMangleContext::create(Ctx, CI.getDiagnostics());
438 
439     AstContext = &Ctx;
440     TraverseDecl(Ctx.getTranslationUnitDecl());
441 
442     // Emit the JSON data for all files now.
443     std::map<FileID, std::unique_ptr<FileInfo>>::iterator It;
444     for (It = FileMap.begin(); It != FileMap.end(); It++) {
445       if (!It->second->Interesting) {
446         continue;
447       }
448 
449       FileInfo &Info = *It->second;
450 
451       std::string Filename = Outdir;
452       Filename += It->second->Realname;
453 
454       ensurePath(Filename);
455 
456       // We lock the output file in case some other clang process is trying to
457       // write to it at the same time.
458       AutoLockFile Lock(Filename);
459 
460       if (!Lock.success()) {
461         continue;
462       }
463 
464       std::vector<std::string> Lines;
465 
466       // Read all the existing lines in from the output file. Rather than
467       // overwrite them, we want to merge our results with what was already
468       // there. This ensures that header files that are included multiple times
469       // in different ways are analyzed completely.
470       char Buffer[65536];
471       FILE *Fp = Lock.openFile("r");
472       if (!Fp) {
473         fprintf(stderr, "Unable to open input file %s\n", Filename.c_str());
474         exit(1);
475       }
476       while (fgets(Buffer, sizeof(Buffer), Fp)) {
477         Lines.push_back(std::string(Buffer));
478       }
479       fclose(Fp);
480 
481       // Insert the newly generated analysis data into what was read. Sort the
482       // results and then remove duplicates.
483       Lines.insert(Lines.end(), Info.Output.begin(), Info.Output.end());
484       std::sort(Lines.begin(), Lines.end());
485 
486       std::vector<std::string> Nodupes;
487       std::unique_copy(Lines.begin(), Lines.end(), std::back_inserter(Nodupes));
488 
489       // Overwrite the output file with the merged data. Since we have the lock,
490       // this will happen atomically.
491       Fp = Lock.openFile("w");
492       if (!Fp) {
493         fprintf(stderr, "Unable to open output file %s\n", Filename.c_str());
494         exit(1);
495       }
496       size_t Length = 0;
497       for (std::string &Line : Nodupes) {
498         Length += Line.length();
499         if (fwrite(Line.c_str(), Line.length(), 1, Fp) != 1) {
500           fprintf(stderr, "Unable to write to output file %s\n", Filename.c_str());
501         }
502       }
503       fclose(Fp);
504 
505       if (!Lock.truncateFile(Length)) {
506         return;
507       }
508     }
509   }
510 
511   // Return a list of mangled names of all the methods that the given method
512   // overrides.
findOverriddenMethods(const CXXMethodDecl * Method,std::vector<std::string> & Symbols)513   void findOverriddenMethods(const CXXMethodDecl *Method,
514                              std::vector<std::string> &Symbols) {
515     std::string Mangled = getMangledName(CurMangleContext, Method);
516     Symbols.push_back(Mangled);
517 
518     CXXMethodDecl::method_iterator Iter = Method->begin_overridden_methods();
519     CXXMethodDecl::method_iterator End = Method->end_overridden_methods();
520     for (; Iter != End; Iter++) {
521       const CXXMethodDecl *Decl = *Iter;
522       if (Decl->isTemplateInstantiation()) {
523         Decl = dyn_cast<CXXMethodDecl>(Decl->getTemplateInstantiationPattern());
524       }
525       return findOverriddenMethods(Decl, Symbols);
526     }
527   }
528 
529   // Unfortunately, we have to override all these methods in order to track the
530   // context we're inside.
531 
TraverseEnumDecl(EnumDecl * D)532   bool TraverseEnumDecl(EnumDecl *D) {
533     AutoSetContext Asc(this, D);
534     return Super::TraverseEnumDecl(D);
535   }
TraverseRecordDecl(RecordDecl * D)536   bool TraverseRecordDecl(RecordDecl *D) {
537     AutoSetContext Asc(this, D);
538     return Super::TraverseRecordDecl(D);
539   }
TraverseCXXRecordDecl(CXXRecordDecl * D)540   bool TraverseCXXRecordDecl(CXXRecordDecl *D) {
541     AutoSetContext Asc(this, D);
542     return Super::TraverseCXXRecordDecl(D);
543   }
TraverseFunctionDecl(FunctionDecl * D)544   bool TraverseFunctionDecl(FunctionDecl *D) {
545     AutoSetContext Asc(this, D);
546     const FunctionDecl *Def;
547     // (See the larger AutoTemplateContext comment for more information.) If a
548     // method on a templated class is declared out-of-line, we need to analyze
549     // the definition inside the scope of the template or else we won't properly
550     // handle member access on the templated type.
551     if (TemplateStack && D->isDefined(Def) && Def && D != Def) {
552       TraverseFunctionDecl(const_cast<FunctionDecl *>(Def));
553     }
554     return Super::TraverseFunctionDecl(D);
555   }
TraverseCXXMethodDecl(CXXMethodDecl * D)556   bool TraverseCXXMethodDecl(CXXMethodDecl *D) {
557     AutoSetContext Asc(this, D);
558     const FunctionDecl *Def;
559     // See TraverseFunctionDecl.
560     if (TemplateStack && D->isDefined(Def) && Def && D != Def) {
561       TraverseFunctionDecl(const_cast<FunctionDecl *>(Def));
562     }
563     return Super::TraverseCXXMethodDecl(D);
564   }
TraverseCXXConstructorDecl(CXXConstructorDecl * D)565   bool TraverseCXXConstructorDecl(CXXConstructorDecl *D) {
566     AutoSetContext Asc(this, D);
567     const FunctionDecl *Def;
568     // See TraverseFunctionDecl.
569     if (TemplateStack && D->isDefined(Def) && Def && D != Def) {
570       TraverseFunctionDecl(const_cast<FunctionDecl *>(Def));
571     }
572     return Super::TraverseCXXConstructorDecl(D);
573   }
TraverseCXXConversionDecl(CXXConversionDecl * D)574   bool TraverseCXXConversionDecl(CXXConversionDecl *D) {
575     AutoSetContext Asc(this, D);
576     const FunctionDecl *Def;
577     // See TraverseFunctionDecl.
578     if (TemplateStack && D->isDefined(Def) && Def && D != Def) {
579       TraverseFunctionDecl(const_cast<FunctionDecl *>(Def));
580     }
581     return Super::TraverseCXXConversionDecl(D);
582   }
TraverseCXXDestructorDecl(CXXDestructorDecl * D)583   bool TraverseCXXDestructorDecl(CXXDestructorDecl *D) {
584     AutoSetContext Asc(this, D);
585     const FunctionDecl *Def;
586     // See TraverseFunctionDecl.
587     if (TemplateStack && D->isDefined(Def) && Def && D != Def) {
588       TraverseFunctionDecl(const_cast<FunctionDecl *>(Def));
589     }
590     return Super::TraverseCXXDestructorDecl(D);
591   }
592 
593   // Used to keep track of the context in which a token appears.
594   struct Context {
595     // Ultimately this becomes the "context" JSON property.
596     std::string Name;
597 
598     // Ultimately this becomes the "contextsym" JSON property.
599     std::vector<std::string> Symbols;
600 
ContextIndexConsumer::Context601     Context() {}
ContextIndexConsumer::Context602     Context(std::string Name, std::vector<std::string> Symbols)
603         : Name(Name), Symbols(Symbols) {}
604   };
605 
translateContext(NamedDecl * D)606   Context translateContext(NamedDecl *D) {
607     const FunctionDecl *F = dyn_cast<FunctionDecl>(D);
608     if (F && F->isTemplateInstantiation()) {
609       D = F->getTemplateInstantiationPattern();
610     }
611 
612     std::vector<std::string> Symbols = {getMangledName(CurMangleContext, D)};
613     if (CXXMethodDecl::classof(D)) {
614       Symbols.clear();
615       findOverriddenMethods(dyn_cast<CXXMethodDecl>(D), Symbols);
616     }
617     return Context(D->getQualifiedNameAsString(), Symbols);
618   }
619 
getContext(SourceLocation Loc)620   Context getContext(SourceLocation Loc) {
621     if (SM.isMacroBodyExpansion(Loc)) {
622       // If we're inside a macro definition, we don't return any context. It
623       // will probably not be what the user expects if we do.
624       return Context();
625     }
626 
627     if (CurDeclContext) {
628       return translateContext(CurDeclContext->Decl);
629     }
630     return Context();
631   }
632 
633   // Similar to GetContext(SourceLocation), but it skips the declaration passed
634   // in. This is useful if we want the context of a declaration that's already
635   // on the stack.
getContext(Decl * D)636   Context getContext(Decl *D) {
637     if (SM.isMacroBodyExpansion(D->getLocation())) {
638       // If we're inside a macro definition, we don't return any context. It
639       // will probably not be what the user expects if we do.
640       return Context();
641     }
642 
643     AutoSetContext *Ctxt = CurDeclContext;
644     while (Ctxt) {
645       if (Ctxt->Decl != D) {
646         return translateContext(Ctxt->Decl);
647       }
648       Ctxt = Ctxt->Prev;
649     }
650     return Context();
651   }
652 
concatSymbols(const std::vector<std::string> Symbols)653   static std::string concatSymbols(const std::vector<std::string> Symbols) {
654     if (Symbols.empty()) {
655       return "";
656     }
657 
658     size_t Total = 0;
659     for (auto It = Symbols.begin(); It != Symbols.end(); It++) {
660       Total += It->length();
661     }
662     Total += Symbols.size() - 1;
663 
664     std::string SymbolList;
665     SymbolList.reserve(Total);
666 
667     for (auto It = Symbols.begin(); It != Symbols.end(); It++) {
668       std::string Symbol = *It;
669 
670       if (It != Symbols.begin()) {
671         SymbolList.push_back(',');
672       }
673       SymbolList.append(Symbol);
674     }
675 
676     return SymbolList;
677   }
678 
679   // Analyzing template code is tricky. Suppose we have this code:
680   //
681   //   template<class T>
682   //   bool Foo(T* ptr) { return T::StaticMethod(ptr); }
683   //
684   // If we analyze the body of Foo without knowing the type T, then we will not
685   // be able to generate any information for StaticMethod. However, analyzing
686   // Foo for every possible instantiation is inefficient and it also generates
687   // too much data in some cases. For example, the following code would generate
688   // one definition of Baz for every instantiation, which is undesirable:
689   //
690   //   template<class T>
691   //   class Bar { struct Baz { ... }; };
692   //
693   // To solve this problem, we analyze templates only once. We do so in a
694   // GatherDependent mode where we look for "dependent scoped member
695   // expressions" (i.e., things like StaticMethod). We keep track of the
696   // locations of these expressions. If we find one or more of them, we analyze
697   // the template for each instantiation, in an AnalyzeDependent mode. This mode
698   // ignores all source locations except for the ones where we found dependent
699   // scoped member expressions before. For these locations, we generate a
700   // separate JSON result for each instantiation.
701   struct AutoTemplateContext {
AutoTemplateContextIndexConsumer::AutoTemplateContext702     AutoTemplateContext(IndexConsumer *Self)
703         : Self(Self), CurMode(Mode::GatherDependent),
704           Parent(Self->TemplateStack) {
705       Self->TemplateStack = this;
706     }
707 
~AutoTemplateContextIndexConsumer::AutoTemplateContext708     ~AutoTemplateContext() { Self->TemplateStack = Parent; }
709 
710     // We traverse templates in two modes:
711     enum class Mode {
712       // Gather mode does not traverse into specializations. It looks for
713       // locations where it would help to have more info from template
714       // specializations.
715       GatherDependent,
716 
717       // Analyze mode traverses into template specializations and records
718       // information about token locations saved in gather mode.
719       AnalyzeDependent,
720     };
721 
722     // We found a dependent scoped member expression! Keep track of it for
723     // later.
visitDependentIndexConsumer::AutoTemplateContext724     void visitDependent(SourceLocation Loc) {
725       if (CurMode == Mode::AnalyzeDependent) {
726         return;
727       }
728 
729       DependentLocations.insert(Loc.getRawEncoding());
730       if (Parent) {
731         Parent->visitDependent(Loc);
732       }
733     }
734 
735     // Do we need to perform the extra AnalyzeDependent passes (one per
736     // instantiation)?
needsAnalysisIndexConsumer::AutoTemplateContext737     bool needsAnalysis() const {
738       if (!DependentLocations.empty()) {
739         return true;
740       }
741       if (Parent) {
742         return Parent->needsAnalysis();
743       }
744       return false;
745     }
746 
switchModeIndexConsumer::AutoTemplateContext747     void switchMode() { CurMode = Mode::AnalyzeDependent; }
748 
749     // Do we want to analyze each template instantiation separately?
shouldVisitTemplateInstantiationsIndexConsumer::AutoTemplateContext750     bool shouldVisitTemplateInstantiations() const {
751       if (CurMode == Mode::AnalyzeDependent) {
752         return true;
753       }
754       if (Parent) {
755         return Parent->shouldVisitTemplateInstantiations();
756       }
757       return false;
758     }
759 
760     // For a given expression/statement, should we emit JSON data for it?
shouldVisitIndexConsumer::AutoTemplateContext761     bool shouldVisit(SourceLocation Loc) {
762       if (CurMode == Mode::GatherDependent) {
763         return true;
764       }
765       if (DependentLocations.find(Loc.getRawEncoding()) !=
766           DependentLocations.end()) {
767         return true;
768       }
769       if (Parent) {
770         return Parent->shouldVisit(Loc);
771       }
772       return false;
773     }
774 
775   private:
776     IndexConsumer *Self;
777     Mode CurMode;
778     std::unordered_set<unsigned> DependentLocations;
779     AutoTemplateContext *Parent;
780   };
781 
782   AutoTemplateContext *TemplateStack;
783 
shouldVisitTemplateInstantiations() const784   bool shouldVisitTemplateInstantiations() const {
785     if (TemplateStack) {
786       return TemplateStack->shouldVisitTemplateInstantiations();
787     }
788     return false;
789   }
790 
TraverseClassTemplateDecl(ClassTemplateDecl * D)791   bool TraverseClassTemplateDecl(ClassTemplateDecl *D) {
792     AutoTemplateContext Atc(this);
793     Super::TraverseClassTemplateDecl(D);
794 
795     if (!Atc.needsAnalysis()) {
796       return true;
797     }
798 
799     Atc.switchMode();
800 
801     if (D != D->getCanonicalDecl()) {
802       return true;
803     }
804 
805     for (auto *Spec : D->specializations()) {
806       for (auto *Rd : Spec->redecls()) {
807         // We don't want to visit injected-class-names in this traversal.
808         if (cast<CXXRecordDecl>(Rd)->isInjectedClassName())
809           continue;
810 
811         TraverseDecl(Rd);
812       }
813     }
814 
815     return true;
816   }
817 
TraverseFunctionTemplateDecl(FunctionTemplateDecl * D)818   bool TraverseFunctionTemplateDecl(FunctionTemplateDecl *D) {
819     AutoTemplateContext Atc(this);
820     Super::TraverseFunctionTemplateDecl(D);
821 
822     if (!Atc.needsAnalysis()) {
823       return true;
824     }
825 
826     Atc.switchMode();
827 
828     if (D != D->getCanonicalDecl()) {
829       return true;
830     }
831 
832     for (auto *Spec : D->specializations()) {
833       for (auto *Rd : Spec->redecls()) {
834         TraverseDecl(Rd);
835       }
836     }
837 
838     return true;
839   }
840 
shouldVisit(SourceLocation Loc)841   bool shouldVisit(SourceLocation Loc) {
842     if (TemplateStack) {
843       return TemplateStack->shouldVisit(Loc);
844     }
845     return true;
846   }
847 
848   enum {
849     NoCrossref = 1 << 0,
850     OperatorToken = 1 << 1,
851   };
852 
853   // This is the only function that emits analysis JSON data. It should be
854   // called for each identifier that corresponds to a symbol.
visitIdentifier(const char * Kind,const char * SyntaxKind,std::string QualName,SourceLocation Loc,const std::vector<std::string> & Symbols,Context TokenContext=Context (),int Flags=0,SourceRange PeekRange=SourceRange ())855   void visitIdentifier(const char *Kind, const char *SyntaxKind,
856                        std::string QualName, SourceLocation Loc,
857                        const std::vector<std::string> &Symbols,
858                        Context TokenContext = Context(), int Flags = 0,
859                        SourceRange PeekRange = SourceRange()) {
860     if (!shouldVisit(Loc)) {
861       return;
862     }
863 
864     // Find the file positions corresponding to the token.
865     unsigned StartOffset = SM.getFileOffset(Loc);
866     unsigned EndOffset =
867         StartOffset + Lexer::MeasureTokenLength(Loc, SM, CI.getLangOpts());
868 
869     std::string LocStr = locationToString(Loc, EndOffset - StartOffset);
870     std::string RangeStr = locationToString(Loc, EndOffset - StartOffset);
871     std::string PeekRangeStr;
872 
873     if (!(Flags & OperatorToken)) {
874       // Get the token's characters so we can make sure it's a valid token.
875       const char *StartChars = SM.getCharacterData(Loc);
876       std::string Text(StartChars, EndOffset - StartOffset);
877       if (!isValidIdentifier(Text)) {
878         return;
879       }
880     }
881 
882     FileInfo *F = getFileInfo(Loc);
883 
884     std::string SymbolList;
885 
886     // Reserve space in symbolList for everything in `symbols`. `symbols` can
887     // contain some very long strings.
888     size_t Total = 0;
889     for (auto It = Symbols.begin(); It != Symbols.end(); It++) {
890       Total += It->length();
891     }
892 
893     // Space for commas.
894     Total += Symbols.size() - 1;
895     SymbolList.reserve(Total);
896 
897     // For each symbol, generate one "target":1 item. We want to find this line
898     // if someone searches for any one of these symbols.
899     for (auto It = Symbols.begin(); It != Symbols.end(); It++) {
900       std::string Symbol = *It;
901 
902       if (!(Flags & NoCrossref)) {
903         JSONFormatter Fmt;
904 
905         Fmt.add("loc", LocStr);
906         Fmt.add("target", 1);
907         Fmt.add("kind", Kind);
908         Fmt.add("pretty", QualName);
909         Fmt.add("sym", Symbol);
910         if (!TokenContext.Name.empty()) {
911           Fmt.add("context", TokenContext.Name);
912         }
913         std::string ContextSymbol = concatSymbols(TokenContext.Symbols);
914         if (!ContextSymbol.empty()) {
915           Fmt.add("contextsym", ContextSymbol);
916         }
917         if (PeekRange.isValid()) {
918           PeekRangeStr = lineRangeToString(PeekRange);
919           if (!PeekRangeStr.empty()) {
920             Fmt.add("peekRange", PeekRangeStr);
921           }
922         }
923 
924         std::string S;
925         Fmt.format(S);
926         F->Output.push_back(std::move(S));
927       }
928 
929       if (It != Symbols.begin()) {
930         SymbolList.push_back(',');
931       }
932       SymbolList.append(Symbol);
933     }
934 
935     // Generate a single "source":1 for all the symbols. If we search from here,
936     // we want to union the results for every symbol in `symbols`.
937     JSONFormatter Fmt;
938 
939     Fmt.add("loc", RangeStr);
940     Fmt.add("source", 1);
941 
942     std::string Syntax;
943     if (Flags & NoCrossref) {
944       Fmt.add("syntax", "");
945     } else {
946       Syntax = Kind;
947       Syntax.push_back(',');
948       Syntax.append(SyntaxKind);
949       Fmt.add("syntax", Syntax);
950     }
951 
952     std::string Pretty(SyntaxKind);
953     Pretty.push_back(' ');
954     Pretty.append(QualName);
955     Fmt.add("pretty", Pretty);
956 
957     Fmt.add("sym", SymbolList);
958 
959     if (Flags & NoCrossref) {
960       Fmt.add("no_crossref", 1);
961     }
962 
963     std::string Buf;
964     Fmt.format(Buf);
965     F->Output.push_back(std::move(Buf));
966   }
967 
visitIdentifier(const char * Kind,const char * SyntaxKind,std::string QualName,SourceLocation Loc,std::string Symbol,Context TokenContext=Context (),int Flags=0,SourceRange PeekRange=SourceRange ())968   void visitIdentifier(const char *Kind, const char *SyntaxKind,
969                        std::string QualName, SourceLocation Loc, std::string Symbol,
970                        Context TokenContext = Context(), int Flags = 0,
971                        SourceRange PeekRange = SourceRange()) {
972     std::vector<std::string> V = {Symbol};
973     visitIdentifier(Kind, SyntaxKind, QualName, Loc, V, TokenContext, Flags, PeekRange);
974   }
975 
normalizeLocation(SourceLocation * Loc)976   void normalizeLocation(SourceLocation *Loc) {
977     *Loc = SM.getSpellingLoc(*Loc);
978   }
979 
getFunctionPeekRange(FunctionDecl * D)980   SourceRange getFunctionPeekRange(FunctionDecl* D) {
981     // We always start at the start of the function decl, which may include the
982     // return type on a separate line.
983     SourceLocation Start = D->getLocStart();
984 
985     // By default, we end at the line containing the function's name.
986     SourceLocation End = D->getLocation();
987 
988     std::pair<FileID, unsigned> FuncLoc = SM.getDecomposedLoc(End);
989 
990     // But if there are parameters, we want to include those as well.
991     for (ParmVarDecl* Param : D->parameters()) {
992       std::pair<FileID, unsigned> ParamLoc = SM.getDecomposedLoc(Param->getLocation());
993 
994       // It's possible there are macros involved or something. We don't include
995       // the parameters in that case.
996       if (ParamLoc.first == FuncLoc.first) {
997         // Assume parameters are in order, so we always take the last one.
998         End = Param->getLocEnd();
999       }
1000     }
1001 
1002     return SourceRange(Start, End);
1003   }
1004 
getTagPeekRange(TagDecl * D)1005   SourceRange getTagPeekRange(TagDecl* D) {
1006     SourceLocation Start = D->getLocStart();
1007 
1008     // By default, we end at the line containing the name.
1009     SourceLocation End = D->getLocation();
1010 
1011     std::pair<FileID, unsigned> FuncLoc = SM.getDecomposedLoc(End);
1012 
1013     if (CXXRecordDecl* D2 = dyn_cast<CXXRecordDecl>(D)) {
1014       // But if there are parameters, we want to include those as well.
1015       for (CXXBaseSpecifier& Base : D2->bases()) {
1016         std::pair<FileID, unsigned> Loc = SM.getDecomposedLoc(Base.getLocEnd());
1017 
1018         // It's possible there are macros involved or something. We don't include
1019         // the parameters in that case.
1020         if (Loc.first == FuncLoc.first) {
1021           // Assume parameters are in order, so we always take the last one.
1022           End = Base.getLocEnd();
1023         }
1024       }
1025     }
1026 
1027     return SourceRange(Start, End);
1028   }
1029 
getCommentRange(NamedDecl * D)1030   SourceRange getCommentRange(NamedDecl* D) {
1031     const RawComment* RC =
1032       AstContext->getRawCommentForDeclNoCache(D);
1033     if (!RC) {
1034       return SourceRange();
1035     }
1036 
1037     return RC->getSourceRange();
1038   }
1039 
combineRanges(SourceRange Range1,SourceRange Range2)1040   SourceRange combineRanges(SourceRange Range1, SourceRange Range2) {
1041     if (Range1.isInvalid()) {
1042       return Range2;
1043     }
1044     if (Range2.isInvalid()) {
1045       return Range1;
1046     }
1047 
1048     std::pair<FileID, unsigned> Begin1 = SM.getDecomposedLoc(Range1.getBegin());
1049     std::pair<FileID, unsigned> End1 = SM.getDecomposedLoc(Range1.getEnd());
1050     std::pair<FileID, unsigned> Begin2 = SM.getDecomposedLoc(Range2.getBegin());
1051     std::pair<FileID, unsigned> End2 = SM.getDecomposedLoc(Range2.getEnd());
1052 
1053     if (End1.first != Begin2.first) {
1054       // Something weird is probably happening with the preprocessor. Just
1055       // return the first range.
1056       return Range1;
1057     }
1058 
1059     // See which range comes first.
1060     if (Begin1.second <= End2.second) {
1061       return SourceRange(Range1.getBegin(), Range2.getEnd());
1062     } else {
1063       return SourceRange(Range2.getBegin(), Range1.getEnd());
1064     }
1065   }
1066 
validateRange(SourceLocation Loc,SourceRange Range)1067   SourceRange validateRange(SourceLocation Loc, SourceRange Range) {
1068     std::pair<FileID, unsigned> Decomposed = SM.getDecomposedLoc(Loc);
1069     std::pair<FileID, unsigned> Begin = SM.getDecomposedLoc(Range.getBegin());
1070     std::pair<FileID, unsigned> End = SM.getDecomposedLoc(Range.getEnd());
1071 
1072     if (Begin.first != Decomposed.first || End.first != Decomposed.first) {
1073       return SourceRange();
1074     }
1075 
1076     if (Begin.second >= End.second) {
1077       return SourceRange();
1078     }
1079 
1080     return Range;
1081   }
1082 
VisitNamedDecl(NamedDecl * D)1083   bool VisitNamedDecl(NamedDecl *D) {
1084     SourceLocation Loc = D->getLocation();
1085 
1086     if (isa<EnumConstantDecl>(D) && SM.isMacroBodyExpansion(Loc)) {
1087       // for enum constants generated by macro expansion, update location
1088       // to point to the expansion location as that is more useful. We might
1089       // want to do this for more token types but until we have good regression
1090       // testing for the Indexer it's best to be as conservative and explicit
1091       // as possible with the changes.
1092       Loc = SM.getFileLoc(Loc);
1093     }
1094 
1095     normalizeLocation(&Loc);
1096     if (!isInterestingLocation(Loc)) {
1097       return true;
1098     }
1099 
1100     if (isa<ParmVarDecl>(D) && !D->getDeclName().getAsIdentifierInfo()) {
1101       // Unnamed parameter in function proto.
1102       return true;
1103     }
1104 
1105     int Flags = 0;
1106     const char *Kind = "def";
1107     const char *PrettyKind = "?";
1108     SourceRange PeekRange(D->getLocStart(), D->getLocEnd());
1109     if (FunctionDecl *D2 = dyn_cast<FunctionDecl>(D)) {
1110       if (D2->isTemplateInstantiation()) {
1111         D = D2->getTemplateInstantiationPattern();
1112       }
1113       Kind = D2->isThisDeclarationADefinition() ? "def" : "decl";
1114       PrettyKind = "function";
1115       PeekRange = getFunctionPeekRange(D2);
1116     } else if (TagDecl *D2 = dyn_cast<TagDecl>(D)) {
1117       Kind = D2->isThisDeclarationADefinition() ? "def" : "decl";
1118       PrettyKind = "type";
1119 
1120       if (D2->isThisDeclarationADefinition() && D2->getDefinition() == D2) {
1121         PeekRange = getTagPeekRange(D2);
1122       } else {
1123         PeekRange = SourceRange();
1124       }
1125     } else if (isa<TypedefNameDecl>(D)) {
1126       Kind = "def";
1127       PrettyKind = "type";
1128       PeekRange = SourceRange(Loc, Loc);
1129     } else if (VarDecl *D2 = dyn_cast<VarDecl>(D)) {
1130       if (D2->isLocalVarDeclOrParm()) {
1131         Flags = NoCrossref;
1132       }
1133 
1134       Kind = D2->isThisDeclarationADefinition() == VarDecl::DeclarationOnly
1135                  ? "decl"
1136                  : "def";
1137       PrettyKind = "variable";
1138     } else if (isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D)) {
1139       Kind = "def";
1140       PrettyKind = "namespace";
1141       PeekRange = SourceRange(Loc, Loc);
1142     } else if (isa<FieldDecl>(D)) {
1143       Kind = "def";
1144       PrettyKind = "field";
1145     } else if (isa<EnumConstantDecl>(D)) {
1146       Kind = "def";
1147       PrettyKind = "enum constant";
1148     } else {
1149       return true;
1150     }
1151 
1152     SourceRange CommentRange = getCommentRange(D);
1153     PeekRange = combineRanges(PeekRange, CommentRange);
1154     PeekRange = validateRange(Loc, PeekRange);
1155 
1156     std::vector<std::string> Symbols = {getMangledName(CurMangleContext, D)};
1157     if (CXXMethodDecl::classof(D)) {
1158       Symbols.clear();
1159       findOverriddenMethods(dyn_cast<CXXMethodDecl>(D), Symbols);
1160     }
1161 
1162     // For destructors, loc points to the ~ character. We want to skip to the
1163     // class name.
1164     if (isa<CXXDestructorDecl>(D)) {
1165       const char *P = SM.getCharacterData(Loc);
1166       assert(*p == '~');
1167       P++;
1168 
1169       unsigned Skipped = 1;
1170       while (*P == ' ' || *P == '\t' || *P == '\r' || *P == '\n') {
1171         P++;
1172         Skipped++;
1173       }
1174 
1175       Loc = Loc.getLocWithOffset(Skipped);
1176 
1177       PrettyKind = "destructor";
1178     }
1179 
1180     visitIdentifier(Kind, PrettyKind, getQualifiedName(D), Loc, Symbols,
1181                     getContext(D), Flags, PeekRange);
1182 
1183     return true;
1184   }
1185 
VisitCXXConstructExpr(CXXConstructExpr * E)1186   bool VisitCXXConstructExpr(CXXConstructExpr *E) {
1187     SourceLocation Loc = E->getLocStart();
1188     normalizeLocation(&Loc);
1189     if (!isInterestingLocation(Loc)) {
1190       return true;
1191     }
1192 
1193     FunctionDecl *Ctor = E->getConstructor();
1194     if (Ctor->isTemplateInstantiation()) {
1195       Ctor = Ctor->getTemplateInstantiationPattern();
1196     }
1197     std::string Mangled = getMangledName(CurMangleContext, Ctor);
1198 
1199     // FIXME: Need to do something different for list initialization.
1200 
1201     visitIdentifier("use", "constructor", getQualifiedName(Ctor), Loc, Mangled,
1202                     getContext(Loc));
1203 
1204     return true;
1205   }
1206 
VisitCallExpr(CallExpr * E)1207   bool VisitCallExpr(CallExpr *E) {
1208     Decl *Callee = E->getCalleeDecl();
1209     if (!Callee || !FunctionDecl::classof(Callee)) {
1210       return true;
1211     }
1212 
1213     const NamedDecl *NamedCallee = dyn_cast<NamedDecl>(Callee);
1214 
1215     SourceLocation Loc;
1216 
1217     const FunctionDecl *F = dyn_cast<FunctionDecl>(NamedCallee);
1218     if (F->isTemplateInstantiation()) {
1219       NamedCallee = F->getTemplateInstantiationPattern();
1220     }
1221 
1222     std::string Mangled = getMangledName(CurMangleContext, NamedCallee);
1223     int Flags = 0;
1224 
1225     Expr *CalleeExpr = E->getCallee()->IgnoreParenImpCasts();
1226 
1227     if (CXXOperatorCallExpr::classof(E)) {
1228       // Just take the first token.
1229       CXXOperatorCallExpr *Op = dyn_cast<CXXOperatorCallExpr>(E);
1230       Loc = Op->getOperatorLoc();
1231       Flags |= OperatorToken;
1232     } else if (MemberExpr::classof(CalleeExpr)) {
1233       MemberExpr *Member = dyn_cast<MemberExpr>(CalleeExpr);
1234       Loc = Member->getMemberLoc();
1235     } else if (DeclRefExpr::classof(CalleeExpr)) {
1236       // We handle this in VisitDeclRefExpr.
1237       return true;
1238     } else {
1239       return true;
1240     }
1241 
1242     normalizeLocation(&Loc);
1243 
1244     if (!isInterestingLocation(Loc)) {
1245       return true;
1246     }
1247 
1248     visitIdentifier("use", "function", getQualifiedName(NamedCallee), Loc, Mangled,
1249                     getContext(Loc), Flags);
1250 
1251     return true;
1252   }
1253 
VisitTagTypeLoc(TagTypeLoc L)1254   bool VisitTagTypeLoc(TagTypeLoc L) {
1255     SourceLocation Loc = L.getBeginLoc();
1256     normalizeLocation(&Loc);
1257     if (!isInterestingLocation(Loc)) {
1258       return true;
1259     }
1260 
1261     TagDecl *Decl = L.getDecl();
1262     std::string Mangled = getMangledName(CurMangleContext, Decl);
1263     visitIdentifier("use", "type", getQualifiedName(Decl), Loc, Mangled,
1264                     getContext(Loc));
1265     return true;
1266   }
1267 
VisitTypedefTypeLoc(TypedefTypeLoc L)1268   bool VisitTypedefTypeLoc(TypedefTypeLoc L) {
1269     SourceLocation Loc = L.getBeginLoc();
1270     normalizeLocation(&Loc);
1271     if (!isInterestingLocation(Loc)) {
1272       return true;
1273     }
1274 
1275     NamedDecl *Decl = L.getTypedefNameDecl();
1276     std::string Mangled = getMangledName(CurMangleContext, Decl);
1277     visitIdentifier("use", "type", getQualifiedName(Decl), Loc, Mangled,
1278                     getContext(Loc));
1279     return true;
1280   }
1281 
VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc L)1282   bool VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc L) {
1283     SourceLocation Loc = L.getBeginLoc();
1284     normalizeLocation(&Loc);
1285     if (!isInterestingLocation(Loc)) {
1286       return true;
1287     }
1288 
1289     NamedDecl *Decl = L.getDecl();
1290     std::string Mangled = getMangledName(CurMangleContext, Decl);
1291     visitIdentifier("use", "type", getQualifiedName(Decl), Loc, Mangled,
1292                     getContext(Loc));
1293     return true;
1294   }
1295 
VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc L)1296   bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc L) {
1297     SourceLocation Loc = L.getBeginLoc();
1298     normalizeLocation(&Loc);
1299     if (!isInterestingLocation(Loc)) {
1300       return true;
1301     }
1302 
1303     TemplateDecl *Td = L.getTypePtr()->getTemplateName().getAsTemplateDecl();
1304     if (ClassTemplateDecl *D = dyn_cast<ClassTemplateDecl>(Td)) {
1305       NamedDecl *Decl = D->getTemplatedDecl();
1306       std::string Mangled = getMangledName(CurMangleContext, Decl);
1307       visitIdentifier("use", "type", getQualifiedName(Decl), Loc, Mangled,
1308                       getContext(Loc));
1309     } else if (TypeAliasTemplateDecl *D = dyn_cast<TypeAliasTemplateDecl>(Td)) {
1310       NamedDecl *Decl = D->getTemplatedDecl();
1311       std::string Mangled = getMangledName(CurMangleContext, Decl);
1312       visitIdentifier("use", "type", getQualifiedName(Decl), Loc, Mangled,
1313                       getContext(Loc));
1314     }
1315 
1316     return true;
1317   }
1318 
VisitDeclRefExpr(DeclRefExpr * E)1319   bool VisitDeclRefExpr(DeclRefExpr *E) {
1320     SourceLocation Loc = E->getExprLoc();
1321     normalizeLocation(&Loc);
1322     if (!isInterestingLocation(Loc)) {
1323       return true;
1324     }
1325 
1326     if (E->hasQualifier()) {
1327       Loc = E->getNameInfo().getLoc();
1328       normalizeLocation(&Loc);
1329     }
1330 
1331     NamedDecl *Decl = E->getDecl();
1332     if (const VarDecl *D2 = dyn_cast<VarDecl>(Decl)) {
1333       int Flags = 0;
1334       if (D2->isLocalVarDeclOrParm()) {
1335         Flags = NoCrossref;
1336       }
1337       std::string Mangled = getMangledName(CurMangleContext, Decl);
1338       visitIdentifier("use", "variable", getQualifiedName(Decl), Loc, Mangled,
1339                       getContext(Loc), Flags);
1340     } else if (isa<FunctionDecl>(Decl)) {
1341       const FunctionDecl *F = dyn_cast<FunctionDecl>(Decl);
1342       if (F->isTemplateInstantiation()) {
1343         Decl = F->getTemplateInstantiationPattern();
1344       }
1345 
1346       std::string Mangled = getMangledName(CurMangleContext, Decl);
1347       visitIdentifier("use", "function", getQualifiedName(Decl), Loc, Mangled,
1348                       getContext(Loc));
1349     } else if (isa<EnumConstantDecl>(Decl)) {
1350       std::string Mangled = getMangledName(CurMangleContext, Decl);
1351       visitIdentifier("use", "enum", getQualifiedName(Decl), Loc, Mangled,
1352                       getContext(Loc));
1353     }
1354 
1355     return true;
1356   }
1357 
VisitCXXConstructorDecl(CXXConstructorDecl * D)1358   bool VisitCXXConstructorDecl(CXXConstructorDecl *D) {
1359     if (!isInterestingLocation(D->getLocation())) {
1360       return true;
1361     }
1362 
1363     for (CXXConstructorDecl::init_const_iterator It = D->init_begin();
1364          It != D->init_end(); ++It) {
1365       const CXXCtorInitializer *Ci = *It;
1366       if (!Ci->getMember() || !Ci->isWritten()) {
1367         continue;
1368       }
1369 
1370       SourceLocation Loc = Ci->getMemberLocation();
1371       normalizeLocation(&Loc);
1372       if (!isInterestingLocation(Loc)) {
1373         continue;
1374       }
1375 
1376       FieldDecl *Member = Ci->getMember();
1377       std::string Mangled = getMangledName(CurMangleContext, Member);
1378       visitIdentifier("use", "field", getQualifiedName(Member), Loc, Mangled,
1379                       getContext(D));
1380     }
1381 
1382     return true;
1383   }
1384 
VisitMemberExpr(MemberExpr * E)1385   bool VisitMemberExpr(MemberExpr *E) {
1386     SourceLocation Loc = E->getExprLoc();
1387     normalizeLocation(&Loc);
1388     if (!isInterestingLocation(Loc)) {
1389       return true;
1390     }
1391 
1392     ValueDecl *Decl = E->getMemberDecl();
1393     if (FieldDecl *Field = dyn_cast<FieldDecl>(Decl)) {
1394       std::string Mangled = getMangledName(CurMangleContext, Field);
1395       visitIdentifier("use", "field", getQualifiedName(Field), Loc, Mangled,
1396                       getContext(Loc));
1397     }
1398     return true;
1399   }
1400 
VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr * E)1401   bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
1402     SourceLocation Loc = E->getMemberLoc();
1403     normalizeLocation(&Loc);
1404     if (!isInterestingLocation(Loc)) {
1405       return true;
1406     }
1407 
1408     if (TemplateStack) {
1409       TemplateStack->visitDependent(Loc);
1410     }
1411     return true;
1412   }
1413 
macroDefined(const Token & Tok,const MacroDirective * Macro)1414   void macroDefined(const Token &Tok, const MacroDirective *Macro) {
1415     if (Macro->getMacroInfo()->isBuiltinMacro()) {
1416       return;
1417     }
1418     SourceLocation Loc = Tok.getLocation();
1419     normalizeLocation(&Loc);
1420     if (!isInterestingLocation(Loc)) {
1421       return;
1422     }
1423 
1424     IdentifierInfo *Ident = Tok.getIdentifierInfo();
1425     if (Ident) {
1426       std::string Mangled =
1427           std::string("M_") + mangleLocation(Loc, Ident->getName());
1428       visitIdentifier("def", "macro", Ident->getName(), Loc, Mangled);
1429     }
1430   }
1431 
macroUsed(const Token & Tok,const MacroInfo * Macro)1432   void macroUsed(const Token &Tok, const MacroInfo *Macro) {
1433     if (!Macro) {
1434       return;
1435     }
1436     if (Macro->isBuiltinMacro()) {
1437       return;
1438     }
1439     SourceLocation Loc = Tok.getLocation();
1440     normalizeLocation(&Loc);
1441     if (!isInterestingLocation(Loc)) {
1442       return;
1443     }
1444 
1445     IdentifierInfo *Ident = Tok.getIdentifierInfo();
1446     if (Ident) {
1447       std::string Mangled =
1448           std::string("M_") +
1449           mangleLocation(Macro->getDefinitionLoc(), Ident->getName());
1450       visitIdentifier("use", "macro", Ident->getName(), Loc, Mangled);
1451     }
1452   }
1453 };
1454 
MacroDefined(const Token & Tok,const MacroDirective * Md)1455 void PreprocessorHook::MacroDefined(const Token &Tok,
1456                                     const MacroDirective *Md) {
1457   Indexer->macroDefined(Tok, Md);
1458 }
1459 
MacroExpands(const Token & Tok,const MacroDefinition & Md,SourceRange Range,const MacroArgs * Ma)1460 void PreprocessorHook::MacroExpands(const Token &Tok, const MacroDefinition &Md,
1461                                     SourceRange Range, const MacroArgs *Ma) {
1462   Indexer->macroUsed(Tok, Md.getMacroInfo());
1463 }
1464 
1465 #if CLANG_VERSION_MAJOR >= 5
MacroUndefined(const Token & Tok,const MacroDefinition & Md,const MacroDirective * Undef)1466 void PreprocessorHook::MacroUndefined(const Token &Tok,
1467                                       const MacroDefinition &Md,
1468                                       const MacroDirective *Undef)
1469 #else
1470 void PreprocessorHook::MacroUndefined(const Token &Tok,
1471                                       const MacroDefinition &Md)
1472 #endif
1473 {
1474   Indexer->macroUsed(Tok, Md.getMacroInfo());
1475 }
1476 
Defined(const Token & Tok,const MacroDefinition & Md,SourceRange Range)1477 void PreprocessorHook::Defined(const Token &Tok, const MacroDefinition &Md,
1478                                SourceRange Range) {
1479   Indexer->macroUsed(Tok, Md.getMacroInfo());
1480 }
1481 
Ifdef(SourceLocation Loc,const Token & Tok,const MacroDefinition & Md)1482 void PreprocessorHook::Ifdef(SourceLocation Loc, const Token &Tok,
1483                              const MacroDefinition &Md) {
1484   Indexer->macroUsed(Tok, Md.getMacroInfo());
1485 }
1486 
Ifndef(SourceLocation Loc,const Token & Tok,const MacroDefinition & Md)1487 void PreprocessorHook::Ifndef(SourceLocation Loc, const Token &Tok,
1488                               const MacroDefinition &Md) {
1489   Indexer->macroUsed(Tok, Md.getMacroInfo());
1490 }
1491 
1492 class IndexAction : public PluginASTAction {
1493 protected:
CreateASTConsumer(CompilerInstance & CI,llvm::StringRef F)1494   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
1495                                                  llvm::StringRef F) {
1496     return llvm::make_unique<IndexConsumer>(CI);
1497   }
1498 
ParseArgs(const CompilerInstance & CI,const std::vector<std::string> & Args)1499   bool ParseArgs(const CompilerInstance &CI,
1500                  const std::vector<std::string> &Args) {
1501     if (Args.size() != 3) {
1502       DiagnosticsEngine &D = CI.getDiagnostics();
1503       unsigned DiagID = D.getCustomDiagID(
1504           DiagnosticsEngine::Error,
1505           "Need arguments for the source, output, and object directories");
1506       D.Report(DiagID);
1507       return false;
1508     }
1509 
1510     // Load our directories
1511     Srcdir = getAbsolutePath(Args[0]);
1512     if (Srcdir.empty()) {
1513       DiagnosticsEngine &D = CI.getDiagnostics();
1514       unsigned DiagID = D.getCustomDiagID(
1515           DiagnosticsEngine::Error, "Source directory '%0' does not exist");
1516       D.Report(DiagID) << Args[0];
1517       return false;
1518     }
1519 
1520     ensurePath(Args[1] + PATHSEP_STRING);
1521     Outdir = getAbsolutePath(Args[1]);
1522     Outdir += PATHSEP_STRING;
1523 
1524     Objdir = getAbsolutePath(Args[2]);
1525     if (Objdir.empty()) {
1526       DiagnosticsEngine &D = CI.getDiagnostics();
1527       unsigned DiagID = D.getCustomDiagID(DiagnosticsEngine::Error,
1528                                           "Objdir '%0' does not exist");
1529       D.Report(DiagID) << Args[2];
1530       return false;
1531     }
1532     Objdir += PATHSEP_STRING;
1533 
1534     printf("MOZSEARCH: %s %s %s\n", Srcdir.c_str(), Outdir.c_str(),
1535            Objdir.c_str());
1536 
1537     return true;
1538   }
1539 
printHelp(llvm::raw_ostream & Ros)1540   void printHelp(llvm::raw_ostream &Ros) {
1541     Ros << "Help for mozsearch plugin goes here\n";
1542   }
1543 };
1544 
1545 static FrontendPluginRegistry::Add<IndexAction>
1546     Y("mozsearch-index", "create the mozsearch index database");
1547