2018-08-21 05:27:52 +00:00
|
|
|
/* Copyright 2017-2018 ccls Authors
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
==============================================================================*/
|
|
|
|
|
2017-02-22 08:52:00 +00:00
|
|
|
#include "indexer.h"
|
2017-02-17 09:57:44 +00:00
|
|
|
|
2018-07-14 23:02:59 +00:00
|
|
|
#include "clang_tu.h"
|
2018-05-27 19:24:56 +00:00
|
|
|
#include "log.hh"
|
2017-04-08 22:54:36 +00:00
|
|
|
#include "platform.h"
|
2017-02-23 08:47:07 +00:00
|
|
|
#include "serializer.h"
|
2018-06-08 04:53:41 +00:00
|
|
|
using ccls::Intern;
|
2017-02-23 08:47:07 +00:00
|
|
|
|
2018-06-01 21:22:55 +00:00
|
|
|
#include <clang/AST/AST.h>
|
2018-06-01 23:51:39 +00:00
|
|
|
#include <clang/Frontend/ASTUnit.h>
|
2018-07-06 00:53:33 +00:00
|
|
|
#include <clang/Frontend/CompilerInstance.h>
|
|
|
|
#include <clang/Frontend/FrontendAction.h>
|
|
|
|
#include <clang/Index/IndexDataConsumer.h>
|
|
|
|
#include <clang/Index/IndexingAction.h>
|
|
|
|
#include <clang/Index/USRGeneration.h>
|
|
|
|
#include <clang/Lex/PreprocessorOptions.h>
|
|
|
|
#include <llvm/ADT/DenseSet.h>
|
|
|
|
#include <llvm/Support/CrashRecoveryContext.h>
|
2018-07-13 02:13:01 +00:00
|
|
|
#include <llvm/Support/Path.h>
|
2018-07-08 07:46:53 +00:00
|
|
|
#include <llvm/Support/Timer.h>
|
2018-06-01 21:22:55 +00:00
|
|
|
using namespace clang;
|
2018-06-01 23:51:39 +00:00
|
|
|
using llvm::Timer;
|
2018-06-01 03:06:09 +00:00
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
#include <algorithm>
|
2018-04-08 06:32:35 +00:00
|
|
|
#include <inttypes.h>
|
2018-03-31 20:59:27 +00:00
|
|
|
#include <limits.h>
|
2018-07-07 23:56:47 +00:00
|
|
|
#include <map>
|
2018-05-05 22:29:17 +00:00
|
|
|
#include <unordered_set>
|
2017-04-22 07:39:55 +00:00
|
|
|
|
2017-04-12 07:36:17 +00:00
|
|
|
namespace {
|
|
|
|
|
2018-07-15 18:27:59 +00:00
|
|
|
constexpr int kInitializerMaxLines = 3;
|
|
|
|
|
2018-07-06 00:53:33 +00:00
|
|
|
struct IndexParam {
|
2018-07-08 18:51:07 +00:00
|
|
|
std::unordered_map<llvm::sys::fs::UniqueID, std::string> SeenUniqueID;
|
2018-07-06 00:53:33 +00:00
|
|
|
std::unordered_map<std::string, FileContents> file_contents;
|
|
|
|
std::unordered_map<std::string, int64_t> file2write_time;
|
2018-07-08 19:49:27 +00:00
|
|
|
struct DeclInfo {
|
|
|
|
Usr usr;
|
|
|
|
std::string short_name;
|
|
|
|
std::string qualified;
|
|
|
|
};
|
2018-08-09 17:08:14 +00:00
|
|
|
std::unordered_map<const Decl *, DeclInfo> Decl2Info;
|
2017-04-12 07:57:12 +00:00
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
ASTUnit &Unit;
|
|
|
|
ASTContext *Ctx;
|
2018-02-12 18:15:43 +00:00
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
FileConsumer *file_consumer = nullptr;
|
2018-03-02 17:56:44 +00:00
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
IndexParam(ASTUnit &Unit, FileConsumer *file_consumer)
|
2018-07-06 00:53:33 +00:00
|
|
|
: Unit(Unit), file_consumer(file_consumer) {}
|
2018-02-10 20:53:18 +00:00
|
|
|
|
2018-07-07 23:56:47 +00:00
|
|
|
IndexFile *ConsumeFile(const FileEntry &File) {
|
2018-07-13 02:13:01 +00:00
|
|
|
IndexFile *db = file_consumer->TryConsumeFile(File, &file_contents);
|
2018-07-07 23:56:47 +00:00
|
|
|
|
|
|
|
// If this is the first time we have seen the file (ignoring if we are
|
|
|
|
// generating an index for it):
|
2018-07-10 06:40:26 +00:00
|
|
|
auto [it, inserted] = SeenUniqueID.try_emplace(File.getUniqueID());
|
|
|
|
if (inserted) {
|
2018-07-07 23:56:47 +00:00
|
|
|
std::string file_name = FileName(File);
|
2018-07-10 06:40:26 +00:00
|
|
|
it->second = file_name;
|
2018-07-07 23:56:47 +00:00
|
|
|
|
|
|
|
// Set modification time.
|
|
|
|
std::optional<int64_t> write_time = LastWriteTime(file_name);
|
|
|
|
LOG_IF_S(ERROR, !write_time)
|
2018-08-09 17:08:14 +00:00
|
|
|
<< "failed to fetch write time for " << file_name;
|
2018-07-07 23:56:47 +00:00
|
|
|
if (write_time)
|
|
|
|
file2write_time[file_name] = *write_time;
|
|
|
|
}
|
2018-03-22 04:04:41 +00:00
|
|
|
|
2018-07-07 23:56:47 +00:00
|
|
|
return db;
|
|
|
|
}
|
|
|
|
};
|
2018-01-07 09:07:39 +00:00
|
|
|
|
2018-07-08 19:49:27 +00:00
|
|
|
StringRef GetSourceInRange(const SourceManager &SM, const LangOptions &LangOpts,
|
|
|
|
SourceRange R) {
|
|
|
|
SourceLocation BLoc = R.getBegin(), ELoc = R.getEnd();
|
|
|
|
std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc),
|
|
|
|
EInfo = SM.getDecomposedLoc(ELoc);
|
|
|
|
bool invalid = false;
|
|
|
|
StringRef Buf = SM.getBufferData(BInfo.first, &invalid);
|
|
|
|
if (invalid)
|
|
|
|
return "";
|
2018-08-09 17:08:14 +00:00
|
|
|
return Buf.substr(BInfo.second,
|
|
|
|
EInfo.second +
|
|
|
|
Lexer::MeasureTokenLength(ELoc, SM, LangOpts) -
|
|
|
|
BInfo.second);
|
2018-07-08 19:49:27 +00:00
|
|
|
}
|
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
SymbolKind GetSymbolKind(const Decl *D) {
|
2018-07-07 23:56:47 +00:00
|
|
|
switch (D->getKind()) {
|
2018-07-06 00:53:33 +00:00
|
|
|
case Decl::TranslationUnit:
|
|
|
|
return SymbolKind::File;
|
2018-07-09 07:05:56 +00:00
|
|
|
case Decl::ObjCMethod:
|
2018-07-06 00:53:33 +00:00
|
|
|
case Decl::FunctionTemplate:
|
|
|
|
case Decl::Function:
|
|
|
|
case Decl::CXXMethod:
|
|
|
|
case Decl::CXXConstructor:
|
|
|
|
case Decl::CXXConversion:
|
|
|
|
case Decl::CXXDestructor:
|
|
|
|
return SymbolKind::Func;
|
|
|
|
case Decl::Namespace:
|
|
|
|
case Decl::NamespaceAlias:
|
2018-07-09 07:05:56 +00:00
|
|
|
case Decl::ObjCCategory:
|
|
|
|
case Decl::ObjCInterface:
|
|
|
|
case Decl::ObjCProtocol:
|
2018-07-06 00:53:33 +00:00
|
|
|
case Decl::ClassTemplate:
|
|
|
|
case Decl::TypeAliasTemplate:
|
2018-07-08 19:49:27 +00:00
|
|
|
case Decl::TemplateTemplateParm:
|
2018-07-06 00:53:33 +00:00
|
|
|
case Decl::Enum:
|
|
|
|
case Decl::Record:
|
|
|
|
case Decl::CXXRecord:
|
2018-07-07 23:56:47 +00:00
|
|
|
case Decl::ClassTemplateSpecialization:
|
2018-07-08 19:49:27 +00:00
|
|
|
case Decl::ClassTemplatePartialSpecialization:
|
2018-07-06 00:53:33 +00:00
|
|
|
case Decl::TypeAlias:
|
|
|
|
case Decl::Typedef:
|
|
|
|
case Decl::UnresolvedUsingTypename:
|
|
|
|
return SymbolKind::Type;
|
2018-07-09 07:05:56 +00:00
|
|
|
case Decl::ObjCProperty:
|
2018-07-08 19:49:27 +00:00
|
|
|
case Decl::VarTemplate:
|
|
|
|
case Decl::Binding:
|
2018-07-06 00:53:33 +00:00
|
|
|
case Decl::Field:
|
2018-07-09 07:05:56 +00:00
|
|
|
case Decl::ObjCIvar:
|
2018-07-06 00:53:33 +00:00
|
|
|
case Decl::Var:
|
|
|
|
case Decl::ParmVar:
|
|
|
|
case Decl::ImplicitParam:
|
|
|
|
case Decl::Decomposition:
|
2018-07-16 01:26:48 +00:00
|
|
|
case Decl::VarTemplateSpecialization:
|
|
|
|
case Decl::VarTemplatePartialSpecialization:
|
2018-07-06 00:53:33 +00:00
|
|
|
case Decl::EnumConstant:
|
2018-07-08 19:49:27 +00:00
|
|
|
case Decl::UnresolvedUsingValue:
|
2018-07-06 00:53:33 +00:00
|
|
|
return SymbolKind::Var;
|
|
|
|
default:
|
|
|
|
return SymbolKind::Invalid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-09 07:05:56 +00:00
|
|
|
LanguageId GetDeclLanguage(const Decl *D) {
|
|
|
|
switch (D->getKind()) {
|
2018-08-09 17:08:14 +00:00
|
|
|
default:
|
|
|
|
return LanguageId::C;
|
|
|
|
case Decl::ImplicitParam:
|
|
|
|
case Decl::ObjCAtDefsField:
|
|
|
|
case Decl::ObjCCategory:
|
|
|
|
case Decl::ObjCCategoryImpl:
|
|
|
|
case Decl::ObjCCompatibleAlias:
|
|
|
|
case Decl::ObjCImplementation:
|
|
|
|
case Decl::ObjCInterface:
|
|
|
|
case Decl::ObjCIvar:
|
|
|
|
case Decl::ObjCMethod:
|
|
|
|
case Decl::ObjCProperty:
|
|
|
|
case Decl::ObjCPropertyImpl:
|
|
|
|
case Decl::ObjCProtocol:
|
|
|
|
case Decl::ObjCTypeParam:
|
|
|
|
return LanguageId::ObjC;
|
|
|
|
case Decl::CXXConstructor:
|
|
|
|
case Decl::CXXConversion:
|
|
|
|
case Decl::CXXDestructor:
|
|
|
|
case Decl::CXXMethod:
|
|
|
|
case Decl::CXXRecord:
|
|
|
|
case Decl::ClassTemplate:
|
|
|
|
case Decl::ClassTemplatePartialSpecialization:
|
|
|
|
case Decl::ClassTemplateSpecialization:
|
|
|
|
case Decl::Friend:
|
|
|
|
case Decl::FriendTemplate:
|
|
|
|
case Decl::FunctionTemplate:
|
|
|
|
case Decl::LinkageSpec:
|
|
|
|
case Decl::Namespace:
|
|
|
|
case Decl::NamespaceAlias:
|
|
|
|
case Decl::NonTypeTemplateParm:
|
|
|
|
case Decl::StaticAssert:
|
|
|
|
case Decl::TemplateTemplateParm:
|
|
|
|
case Decl::TemplateTypeParm:
|
|
|
|
case Decl::UnresolvedUsingTypename:
|
|
|
|
case Decl::UnresolvedUsingValue:
|
|
|
|
case Decl::Using:
|
|
|
|
case Decl::UsingDirective:
|
|
|
|
case Decl::UsingShadow:
|
|
|
|
return LanguageId::Cpp;
|
2018-07-09 07:05:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-08 19:49:27 +00:00
|
|
|
// clang/lib/AST/DeclPrinter.cpp
|
|
|
|
QualType GetBaseType(QualType T, bool deduce_auto) {
|
|
|
|
QualType BaseType = T;
|
|
|
|
while (!BaseType.isNull() && !BaseType->isSpecifierType()) {
|
|
|
|
if (const PointerType *PTy = BaseType->getAs<PointerType>())
|
|
|
|
BaseType = PTy->getPointeeType();
|
|
|
|
else if (const BlockPointerType *BPy = BaseType->getAs<BlockPointerType>())
|
|
|
|
BaseType = BPy->getPointeeType();
|
2018-08-09 17:08:14 +00:00
|
|
|
else if (const ArrayType *ATy = dyn_cast<ArrayType>(BaseType))
|
2018-07-08 19:49:27 +00:00
|
|
|
BaseType = ATy->getElementType();
|
|
|
|
else if (const VectorType *VTy = BaseType->getAs<VectorType>())
|
|
|
|
BaseType = VTy->getElementType();
|
|
|
|
else if (const ReferenceType *RTy = BaseType->getAs<ReferenceType>())
|
|
|
|
BaseType = RTy->getPointeeType();
|
|
|
|
else if (const ParenType *PTy = BaseType->getAs<ParenType>())
|
|
|
|
BaseType = PTy->desugar();
|
|
|
|
else if (deduce_auto) {
|
|
|
|
if (const AutoType *ATy = BaseType->getAs<AutoType>())
|
|
|
|
BaseType = ATy->getDeducedType();
|
|
|
|
else
|
|
|
|
break;
|
2018-08-09 17:08:14 +00:00
|
|
|
} else
|
2018-07-08 19:49:27 +00:00
|
|
|
break;
|
2018-07-06 00:53:33 +00:00
|
|
|
}
|
2018-07-08 19:49:27 +00:00
|
|
|
return BaseType;
|
|
|
|
}
|
|
|
|
|
2018-07-23 03:10:04 +00:00
|
|
|
const Decl *GetTypeDecl(QualType T, bool *specialization = nullptr) {
|
2018-07-08 19:49:27 +00:00
|
|
|
Decl *D = nullptr;
|
|
|
|
T = GetBaseType(T.getUnqualifiedType(), true);
|
2018-08-09 17:08:14 +00:00
|
|
|
const Type *TP = T.getTypePtrOrNull();
|
2018-07-08 19:49:27 +00:00
|
|
|
if (!TP)
|
|
|
|
return nullptr;
|
2018-07-06 00:53:33 +00:00
|
|
|
|
|
|
|
try_again:
|
|
|
|
switch (TP->getTypeClass()) {
|
|
|
|
case Type::Typedef:
|
|
|
|
D = cast<TypedefType>(TP)->getDecl();
|
|
|
|
break;
|
|
|
|
case Type::ObjCObject:
|
|
|
|
D = cast<ObjCObjectType>(TP)->getInterface();
|
|
|
|
break;
|
|
|
|
case Type::ObjCInterface:
|
|
|
|
D = cast<ObjCInterfaceType>(TP)->getDecl();
|
|
|
|
break;
|
|
|
|
case Type::Record:
|
|
|
|
case Type::Enum:
|
|
|
|
D = cast<TagType>(TP)->getDecl();
|
|
|
|
break;
|
2018-07-08 19:49:27 +00:00
|
|
|
case Type::TemplateTypeParm:
|
|
|
|
D = cast<TemplateTypeParmType>(TP)->getDecl();
|
|
|
|
break;
|
2018-07-06 00:53:33 +00:00
|
|
|
case Type::TemplateSpecialization:
|
2018-07-23 03:10:04 +00:00
|
|
|
if (specialization)
|
|
|
|
*specialization = true;
|
2018-07-06 00:53:33 +00:00
|
|
|
if (const RecordType *Record = TP->getAs<RecordType>())
|
|
|
|
D = Record->getDecl();
|
|
|
|
else
|
|
|
|
D = cast<TemplateSpecializationType>(TP)
|
|
|
|
->getTemplateName()
|
|
|
|
.getAsTemplateDecl();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Type::Auto:
|
|
|
|
case Type::DeducedTemplateSpecialization:
|
|
|
|
TP = cast<DeducedType>(TP)->getDeducedType().getTypePtrOrNull();
|
|
|
|
if (TP)
|
|
|
|
goto try_again;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Type::InjectedClassName:
|
|
|
|
D = cast<InjectedClassNameType>(TP)->getDecl();
|
|
|
|
break;
|
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
// FIXME: Template type parameters!
|
2018-07-06 00:53:33 +00:00
|
|
|
|
|
|
|
case Type::Elaborated:
|
|
|
|
TP = cast<ElaboratedType>(TP)->getNamedType().getTypePtrOrNull();
|
|
|
|
goto try_again;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return D;
|
|
|
|
}
|
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
const Decl *GetSpecialized(const Decl *D) {
|
2018-07-06 00:53:33 +00:00
|
|
|
if (!D)
|
|
|
|
return D;
|
|
|
|
Decl *Template = nullptr;
|
|
|
|
if (const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) {
|
2018-08-09 17:08:14 +00:00
|
|
|
if (const ClassTemplatePartialSpecializationDecl *PartialSpec =
|
|
|
|
dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord))
|
2018-07-06 00:53:33 +00:00
|
|
|
Template = PartialSpec->getSpecializedTemplate();
|
2018-08-09 17:08:14 +00:00
|
|
|
else if (const ClassTemplateSpecializationDecl *ClassSpec =
|
|
|
|
dyn_cast<ClassTemplateSpecializationDecl>(CXXRecord)) {
|
2018-07-06 00:53:33 +00:00
|
|
|
llvm::PointerUnion<ClassTemplateDecl *,
|
2018-08-09 17:08:14 +00:00
|
|
|
ClassTemplatePartialSpecializationDecl *>
|
|
|
|
Result = ClassSpec->getSpecializedTemplateOrPartial();
|
2018-07-06 00:53:33 +00:00
|
|
|
if (Result.is<ClassTemplateDecl *>())
|
|
|
|
Template = Result.get<ClassTemplateDecl *>();
|
|
|
|
else
|
|
|
|
Template = Result.get<ClassTemplatePartialSpecializationDecl *>();
|
|
|
|
|
|
|
|
} else
|
|
|
|
Template = CXXRecord->getInstantiatedFromMemberClass();
|
|
|
|
} else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
|
|
|
|
Template = Function->getPrimaryTemplate();
|
|
|
|
if (!Template)
|
|
|
|
Template = Function->getInstantiatedFromMemberFunction();
|
|
|
|
} else if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
|
|
|
|
if (Var->isStaticDataMember())
|
|
|
|
Template = Var->getInstantiatedFromStaticDataMember();
|
2018-08-09 17:08:14 +00:00
|
|
|
} else if (const RedeclarableTemplateDecl *Tmpl =
|
|
|
|
dyn_cast<RedeclarableTemplateDecl>(D))
|
2018-07-06 00:53:33 +00:00
|
|
|
Template = Tmpl->getInstantiatedFromMemberTemplate();
|
|
|
|
else
|
|
|
|
return nullptr;
|
|
|
|
return Template;
|
2018-01-26 17:28:29 +00:00
|
|
|
}
|
|
|
|
|
2018-08-03 23:11:32 +00:00
|
|
|
bool ValidateRecord(const RecordDecl *RD) {
|
2018-08-09 17:08:14 +00:00
|
|
|
for (const auto *I : RD->fields()) {
|
2018-08-03 23:11:32 +00:00
|
|
|
QualType FQT = I->getType();
|
|
|
|
if (FQT->isIncompleteType() || FQT->isDependentType())
|
|
|
|
return false;
|
|
|
|
if (const RecordType *ChildType = I->getType()->getAs<RecordType>())
|
|
|
|
if (const RecordDecl *Child = ChildType->getDecl())
|
|
|
|
if (!ValidateRecord(Child))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-07-06 00:53:33 +00:00
|
|
|
class IndexDataConsumer : public index::IndexDataConsumer {
|
2018-07-07 23:56:47 +00:00
|
|
|
public:
|
2018-07-06 00:53:33 +00:00
|
|
|
ASTContext *Ctx;
|
2018-08-09 17:08:14 +00:00
|
|
|
IndexParam ¶m;
|
2017-11-09 03:59:11 +00:00
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
std::string GetComment(const Decl *D) {
|
2018-07-07 22:25:25 +00:00
|
|
|
SourceManager &SM = Ctx->getSourceManager();
|
|
|
|
const RawComment *RC = Ctx->getRawCommentForAnyRedecl(D);
|
2018-08-09 17:08:14 +00:00
|
|
|
if (!RC)
|
|
|
|
return "";
|
2018-07-07 22:25:25 +00:00
|
|
|
StringRef Raw = RC->getRawText(Ctx->getSourceManager());
|
|
|
|
SourceRange R = RC->getSourceRange();
|
|
|
|
std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(R.getBegin());
|
|
|
|
unsigned start_column = SM.getLineNumber(BInfo.first, BInfo.second);
|
|
|
|
std::string ret;
|
|
|
|
int pad = -1;
|
|
|
|
for (const char *p = Raw.data(), *E = Raw.end(); p < E;) {
|
|
|
|
// The first line starts with a comment marker, but the rest needs
|
|
|
|
// un-indenting.
|
|
|
|
unsigned skip = start_column - 1;
|
|
|
|
for (; skip > 0 && p < E && (*p == ' ' || *p == '\t'); p++)
|
|
|
|
skip--;
|
|
|
|
const char *q = p;
|
|
|
|
while (q < E && *q != '\n')
|
|
|
|
q++;
|
|
|
|
if (q < E)
|
|
|
|
q++;
|
|
|
|
// A minimalist approach to skip Doxygen comment markers.
|
|
|
|
// See https://www.stack.nl/~dimitri/doxygen/manual/docblocks.html
|
|
|
|
if (pad < 0) {
|
|
|
|
// First line, detect the length of comment marker and put into |pad|
|
|
|
|
const char *begin = p;
|
2018-07-15 18:27:59 +00:00
|
|
|
while (p < E && (*p == '/' || *p == '*' || *p == '-' || *p == '='))
|
2018-07-07 22:25:25 +00:00
|
|
|
p++;
|
|
|
|
if (p < E && (*p == '<' || *p == '!'))
|
|
|
|
p++;
|
|
|
|
if (p < E && *p == ' ')
|
|
|
|
p++;
|
2018-07-25 17:36:30 +00:00
|
|
|
if (p + 1 == q)
|
|
|
|
p++;
|
|
|
|
else
|
|
|
|
pad = int(p - begin);
|
2018-07-07 22:25:25 +00:00
|
|
|
} else {
|
|
|
|
// Other lines, skip |pad| bytes
|
|
|
|
int prefix = pad;
|
|
|
|
while (prefix > 0 && p < E &&
|
|
|
|
(*p == ' ' || *p == '/' || *p == '*' || *p == '<' || *p == '!'))
|
|
|
|
prefix--, p++;
|
|
|
|
}
|
|
|
|
ret.insert(ret.end(), p, q);
|
|
|
|
p = q;
|
|
|
|
}
|
|
|
|
while (ret.size() && isspace(ret.back()))
|
|
|
|
ret.pop_back();
|
|
|
|
if (EndsWith(ret, "*/")) {
|
|
|
|
ret.resize(ret.size() - 2);
|
|
|
|
} else if (EndsWith(ret, "\n/")) {
|
|
|
|
ret.resize(ret.size() - 2);
|
|
|
|
}
|
|
|
|
while (ret.size() && isspace(ret.back()))
|
|
|
|
ret.pop_back();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-07-08 19:49:27 +00:00
|
|
|
Usr GetUsr(const Decl *D, IndexParam::DeclInfo **info = nullptr) const {
|
2018-07-06 00:53:33 +00:00
|
|
|
D = D->getCanonicalDecl();
|
2018-07-10 06:40:26 +00:00
|
|
|
auto [it, inserted] = param.Decl2Info.try_emplace(D);
|
|
|
|
if (inserted) {
|
2018-07-06 00:53:33 +00:00
|
|
|
SmallString<256> USR;
|
|
|
|
index::generateUSRForDecl(D, USR);
|
2018-07-10 06:40:26 +00:00
|
|
|
auto &info = it->second;
|
2018-07-08 19:49:27 +00:00
|
|
|
info.usr = HashUsr(USR);
|
|
|
|
if (auto *ND = dyn_cast<NamedDecl>(D)) {
|
|
|
|
info.short_name = ND->getNameAsString();
|
|
|
|
info.qualified = ND->getQualifiedNameAsString();
|
|
|
|
SimplifyAnonymous(info.qualified);
|
|
|
|
}
|
2017-11-09 03:55:13 +00:00
|
|
|
}
|
2018-07-08 19:49:27 +00:00
|
|
|
if (info)
|
2018-07-10 06:40:26 +00:00
|
|
|
*info = &it->second;
|
|
|
|
return it->second.usr;
|
2017-11-09 03:55:13 +00:00
|
|
|
}
|
|
|
|
|
2018-07-07 23:56:47 +00:00
|
|
|
Use GetUse(IndexFile *db, Range range, const DeclContext *DC,
|
|
|
|
Role role) const {
|
|
|
|
if (!DC)
|
|
|
|
return Use{{range, 0, SymbolKind::File, role}};
|
|
|
|
const Decl *D = cast<Decl>(DC);
|
|
|
|
switch (GetSymbolKind(D)) {
|
|
|
|
case SymbolKind::Func:
|
|
|
|
return Use{{range, db->ToFunc(GetUsr(D)).usr, SymbolKind::Func, role}};
|
|
|
|
case SymbolKind::Type:
|
|
|
|
return Use{{range, db->ToType(GetUsr(D)).usr, SymbolKind::Type, role}};
|
|
|
|
case SymbolKind::Var:
|
|
|
|
return Use{{range, db->ToVar(GetUsr(D)).usr, SymbolKind::Var, role}};
|
|
|
|
default:
|
|
|
|
return Use{{range, 0, SymbolKind::File, role}};
|
2017-11-09 03:55:13 +00:00
|
|
|
}
|
2018-07-07 23:56:47 +00:00
|
|
|
}
|
2017-11-09 03:55:13 +00:00
|
|
|
|
2018-07-07 23:56:47 +00:00
|
|
|
PrintingPolicy GetDefaultPolicy() const {
|
|
|
|
PrintingPolicy PP(Ctx->getLangOpts());
|
|
|
|
PP.AnonymousTagLocations = false;
|
|
|
|
PP.TerseOutput = true;
|
|
|
|
PP.PolishForDeclaration = true;
|
|
|
|
PP.ConstantsAsWritten = true;
|
|
|
|
PP.SuppressTagKeyword = true;
|
|
|
|
PP.SuppressInitializers = true;
|
|
|
|
PP.FullyQualifiedName = false;
|
|
|
|
return PP;
|
|
|
|
}
|
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
static void SimplifyAnonymous(std::string &name) {
|
2018-04-06 00:00:07 +00:00
|
|
|
for (std::string::size_type i = 0;;) {
|
|
|
|
if ((i = name.find("(anonymous ", i)) == std::string::npos)
|
|
|
|
break;
|
|
|
|
i++;
|
2018-07-07 23:56:47 +00:00
|
|
|
if (name.size() - i > 19 && name.compare(i + 10, 9, "namespace") == 0)
|
|
|
|
name.replace(i, 19, "anon ns");
|
2018-04-06 00:00:07 +00:00
|
|
|
else
|
2018-07-07 23:56:47 +00:00
|
|
|
name.replace(i, 9, "anon");
|
2018-04-06 00:00:07 +00:00
|
|
|
}
|
2018-07-07 23:56:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Def>
|
|
|
|
void SetName(const Decl *D, std::string_view short_name,
|
2018-07-08 19:49:27 +00:00
|
|
|
std::string_view qualified, Def &def) {
|
2018-07-07 23:56:47 +00:00
|
|
|
SmallString<256> Str;
|
|
|
|
llvm::raw_svector_ostream OS(Str);
|
2018-07-08 19:49:27 +00:00
|
|
|
D->print(OS, GetDefaultPolicy());
|
2018-07-07 23:56:47 +00:00
|
|
|
|
|
|
|
std::string name = OS.str();
|
|
|
|
SimplifyAnonymous(name);
|
2018-04-06 00:00:07 +00:00
|
|
|
auto i = name.find(short_name);
|
2018-07-27 07:21:57 +00:00
|
|
|
if (short_name.size())
|
|
|
|
while (i != std::string::npos && ((i && isalnum(name[i - 1])) ||
|
|
|
|
isalnum(name[i + short_name.size()])))
|
|
|
|
i = name.find(short_name, i + short_name.size());
|
2018-07-06 00:53:33 +00:00
|
|
|
if (i == std::string::npos) {
|
|
|
|
// e.g. operator type-parameter-1
|
|
|
|
i = 0;
|
2018-07-08 19:49:27 +00:00
|
|
|
def.short_name_offset = 0;
|
|
|
|
} else if (short_name.size() && (!i || name[i - 1] != ':')) {
|
2018-07-06 00:53:33 +00:00
|
|
|
name.replace(i, short_name.size(), qualified);
|
2018-07-08 19:49:27 +00:00
|
|
|
def.short_name_offset = i + qualified.size() - short_name.size();
|
2018-07-06 00:53:33 +00:00
|
|
|
} else {
|
2018-07-08 19:49:27 +00:00
|
|
|
def.short_name_offset = i;
|
2018-07-06 00:53:33 +00:00
|
|
|
}
|
2018-07-08 19:49:27 +00:00
|
|
|
def.short_name_size = short_name.size();
|
|
|
|
for (int paren = 0; i; i--) {
|
|
|
|
// Skip parentheses in "(anon struct)::name"
|
|
|
|
if (name[i - 1] == ')')
|
|
|
|
paren++;
|
|
|
|
else if (name[i - 1] == '(')
|
|
|
|
paren--;
|
|
|
|
else if (!(paren > 0 || isalnum(name[i - 1]) || name[i - 1] == '_' ||
|
|
|
|
name[i - 1] == ':'))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
def.qual_name_offset = i;
|
|
|
|
def.detailed_name = Intern(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetVarName(const Decl *D, std::string_view short_name,
|
|
|
|
std::string_view qualified, IndexVar::Def &def) {
|
|
|
|
QualType T;
|
2018-08-09 17:08:14 +00:00
|
|
|
const Expr *init = nullptr;
|
2018-07-16 01:26:48 +00:00
|
|
|
bool binding = false;
|
2018-07-08 19:49:27 +00:00
|
|
|
if (auto *VD = dyn_cast<VarDecl>(D)) {
|
|
|
|
T = VD->getType();
|
|
|
|
init = VD->getAnyInitializer();
|
|
|
|
def.storage = VD->getStorageClass();
|
|
|
|
} else if (auto *FD = dyn_cast<FieldDecl>(D)) {
|
|
|
|
T = FD->getType();
|
|
|
|
init = FD->getInClassInitializer();
|
2018-07-16 01:26:48 +00:00
|
|
|
} else if (auto *BD = dyn_cast<BindingDecl>(D)) {
|
|
|
|
T = BD->getType();
|
|
|
|
binding = true;
|
2018-07-08 19:49:27 +00:00
|
|
|
}
|
|
|
|
auto BT = GetBaseType(T, false);
|
2018-07-16 01:26:48 +00:00
|
|
|
if (!BT.isNull() && (binding || BT->getAs<AutoType>())) {
|
2018-07-08 19:49:27 +00:00
|
|
|
SmallString<256> Str;
|
|
|
|
llvm::raw_svector_ostream OS(Str);
|
|
|
|
PrintingPolicy PP = GetDefaultPolicy();
|
|
|
|
T.print(OS, PP);
|
|
|
|
if (Str.size() &&
|
2018-08-09 17:08:14 +00:00
|
|
|
(Str.back() != ' ' && Str.back() != '*' && Str.back() != '&'))
|
2018-07-08 19:49:27 +00:00
|
|
|
Str += ' ';
|
|
|
|
def.qual_name_offset = Str.size();
|
|
|
|
def.short_name_offset = Str.size() + qualified.size() - short_name.size();
|
2018-07-07 23:56:47 +00:00
|
|
|
def.short_name_size = short_name.size();
|
2018-07-08 19:49:27 +00:00
|
|
|
Str += StringRef(qualified.data(), qualified.size());
|
|
|
|
def.detailed_name = Intern(Str.str());
|
|
|
|
} else {
|
|
|
|
SetName(D, short_name, qualified, def);
|
|
|
|
}
|
|
|
|
if (init) {
|
|
|
|
SourceManager &SM = Ctx->getSourceManager();
|
2018-08-09 17:08:14 +00:00
|
|
|
const LangOptions &Lang = Ctx->getLangOpts();
|
2018-07-27 07:21:57 +00:00
|
|
|
SourceRange R = SM.getExpansionRange(init->getSourceRange())
|
|
|
|
#if LLVM_VERSION_MAJOR >= 7
|
|
|
|
.getAsRange()
|
|
|
|
#endif
|
|
|
|
;
|
2018-07-08 19:49:27 +00:00
|
|
|
SourceLocation L = D->getLocation();
|
2018-07-17 06:22:34 +00:00
|
|
|
if (L.isMacroID() || !SM.isBeforeInTranslationUnit(L, R.getBegin()))
|
2018-07-08 19:49:27 +00:00
|
|
|
return;
|
|
|
|
StringRef Buf = GetSourceInRange(SM, Lang, R);
|
2018-07-23 03:10:04 +00:00
|
|
|
Twine Init = Buf.count('\n') <= kInitializerMaxLines - 1
|
|
|
|
? Buf.size() && Buf[0] == ':' ? Twine(" ", Buf)
|
|
|
|
: Twine(" = ", Buf)
|
|
|
|
: Twine();
|
|
|
|
Twine T = def.detailed_name + Init;
|
2018-07-08 19:49:27 +00:00
|
|
|
def.hover =
|
|
|
|
def.storage == SC_Static && strncmp(def.detailed_name, "static ", 7)
|
2018-07-23 03:10:04 +00:00
|
|
|
? Intern(("static " + T).str())
|
2018-07-08 19:49:27 +00:00
|
|
|
: Intern(T.str());
|
2018-04-06 00:00:07 +00:00
|
|
|
}
|
2017-07-30 04:24:02 +00:00
|
|
|
}
|
2017-05-20 21:45:46 +00:00
|
|
|
|
2018-07-13 02:13:01 +00:00
|
|
|
void AddMacroUse(IndexFile *db, SourceManager &SM, Usr usr, SymbolKind kind,
|
2018-07-07 23:56:47 +00:00
|
|
|
SourceLocation Spell) const {
|
|
|
|
const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Spell));
|
2018-08-09 17:08:14 +00:00
|
|
|
if (!FE)
|
|
|
|
return;
|
2018-07-13 02:13:01 +00:00
|
|
|
auto UID = FE->getUniqueID();
|
|
|
|
auto [it, inserted] = db->uid2lid_and_path.try_emplace(UID);
|
|
|
|
if (inserted) {
|
|
|
|
it->second.first = db->uid2lid_and_path.size() - 1;
|
|
|
|
SmallString<256> Path = FE->tryGetRealPathName();
|
|
|
|
if (Path.empty())
|
|
|
|
Path = FE->getName();
|
|
|
|
if (!llvm::sys::path::is_absolute(Path) &&
|
|
|
|
!SM.getFileManager().makeAbsolutePath(Path))
|
|
|
|
return;
|
|
|
|
it->second.second = Path.str();
|
|
|
|
}
|
2018-07-08 19:49:27 +00:00
|
|
|
Range spell =
|
|
|
|
FromTokenRange(SM, Ctx->getLangOpts(), SourceRange(Spell, Spell));
|
2018-07-13 02:13:01 +00:00
|
|
|
Use use{{spell, 0, SymbolKind::File, Role::Dynamic}, it->second.first};
|
2018-07-08 19:49:27 +00:00
|
|
|
switch (kind) {
|
|
|
|
case SymbolKind::Func:
|
|
|
|
db->ToFunc(usr).uses.push_back(use);
|
|
|
|
break;
|
|
|
|
case SymbolKind::Type:
|
|
|
|
db->ToType(usr).uses.push_back(use);
|
|
|
|
break;
|
|
|
|
case SymbolKind::Var:
|
|
|
|
db->ToVar(usr).uses.push_back(use);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("");
|
2018-07-06 00:53:33 +00:00
|
|
|
}
|
2018-01-21 06:34:41 +00:00
|
|
|
}
|
|
|
|
|
2018-07-06 00:53:33 +00:00
|
|
|
public:
|
2018-08-09 17:08:14 +00:00
|
|
|
IndexDataConsumer(IndexParam ¶m) : param(param) {}
|
|
|
|
void initialize(ASTContext &Ctx) override { this->Ctx = param.Ctx = &Ctx; }
|
2018-07-06 00:53:33 +00:00
|
|
|
bool handleDeclOccurence(const Decl *D, index::SymbolRoleSet Roles,
|
|
|
|
ArrayRef<index::SymbolRelation> Relations,
|
|
|
|
#if LLVM_VERSION_MAJOR >= 7
|
|
|
|
SourceLocation Loc,
|
|
|
|
#else
|
|
|
|
FileID LocFID, unsigned LocOffset,
|
2018-02-04 22:54:08 +00:00
|
|
|
#endif
|
2018-07-06 00:53:33 +00:00
|
|
|
ASTNodeInfo ASTNode) override {
|
|
|
|
SourceManager &SM = Ctx->getSourceManager();
|
|
|
|
const LangOptions &Lang = Ctx->getLangOpts();
|
|
|
|
#if LLVM_VERSION_MAJOR < 7
|
|
|
|
SourceLocation Loc;
|
|
|
|
{
|
|
|
|
const SrcMgr::SLocEntry &Entry = SM.getSLocEntry(LocFID);
|
|
|
|
unsigned off = Entry.getOffset() + LocOffset;
|
|
|
|
if (!Entry.isFile())
|
|
|
|
off |= 1u << 31;
|
|
|
|
Loc = SourceLocation::getFromRawEncoding(off);
|
2018-06-06 07:36:39 +00:00
|
|
|
}
|
2018-07-09 02:56:33 +00:00
|
|
|
#else
|
|
|
|
FileID LocFID;
|
2018-07-06 00:53:33 +00:00
|
|
|
#endif
|
|
|
|
SourceLocation Spell = SM.getSpellingLoc(Loc);
|
2018-07-13 02:13:01 +00:00
|
|
|
const FileEntry *FE;
|
|
|
|
Range loc;
|
2018-07-06 00:53:33 +00:00
|
|
|
#if LLVM_VERSION_MAJOR < 7
|
2018-07-16 16:49:32 +00:00
|
|
|
CharSourceRange R;
|
|
|
|
if (SM.isMacroArgExpansion(Loc))
|
|
|
|
R = CharSourceRange::getTokenRange(Spell);
|
|
|
|
else {
|
|
|
|
auto P = SM.getExpansionRange(Loc);
|
|
|
|
R = CharSourceRange::getTokenRange(P.first, P.second);
|
|
|
|
}
|
2018-02-04 22:54:08 +00:00
|
|
|
#else
|
2018-07-15 18:27:59 +00:00
|
|
|
auto R = SM.isMacroArgExpansion(Loc) ? CharSourceRange::getTokenRange(Spell)
|
|
|
|
: SM.getExpansionRange(Loc);
|
2018-07-16 16:49:32 +00:00
|
|
|
#endif
|
2018-07-29 04:32:41 +00:00
|
|
|
loc = FromCharSourceRange(SM, Lang, R);
|
2018-07-13 02:13:01 +00:00
|
|
|
LocFID = SM.getFileID(R.getBegin());
|
|
|
|
FE = SM.getFileEntryForID(LocFID);
|
|
|
|
if (!FE)
|
|
|
|
return true;
|
2018-07-07 23:56:47 +00:00
|
|
|
IndexFile *db = param.ConsumeFile(*FE);
|
2018-07-06 00:53:33 +00:00
|
|
|
if (!db)
|
|
|
|
return true;
|
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
const Decl *OrigD = ASTNode.OrigD;
|
2018-07-08 07:46:53 +00:00
|
|
|
const DeclContext *SemDC = OrigD->getDeclContext();
|
2018-07-21 06:27:47 +00:00
|
|
|
const DeclContext *LexDC = ASTNode.ContainerDC;
|
2018-07-06 00:53:33 +00:00
|
|
|
Role role = static_cast<Role>(Roles);
|
2018-07-09 07:05:56 +00:00
|
|
|
db->language = std::max(db->language, GetDeclLanguage(OrigD));
|
2018-07-06 00:53:33 +00:00
|
|
|
|
|
|
|
bool is_decl = Roles & uint32_t(index::SymbolRole::Declaration);
|
|
|
|
bool is_def = Roles & uint32_t(index::SymbolRole::Definition);
|
2018-07-16 01:26:48 +00:00
|
|
|
if (is_decl && D->getKind() == Decl::Binding)
|
|
|
|
is_def = true;
|
2018-07-06 00:53:33 +00:00
|
|
|
IndexFunc *func = nullptr;
|
|
|
|
IndexType *type = nullptr;
|
|
|
|
IndexVar *var = nullptr;
|
2018-07-07 23:56:47 +00:00
|
|
|
SymbolKind kind = GetSymbolKind(D);
|
2018-08-09 17:08:14 +00:00
|
|
|
IndexParam::DeclInfo *info;
|
2018-07-08 19:49:27 +00:00
|
|
|
Usr usr = GetUsr(D, &info);
|
2018-07-07 23:56:47 +00:00
|
|
|
|
|
|
|
auto do_def_decl = [&](auto *entity) {
|
|
|
|
if (is_def) {
|
2018-07-08 07:46:53 +00:00
|
|
|
entity->def.spell = GetUse(db, loc, SemDC, role);
|
2018-07-25 17:36:30 +00:00
|
|
|
SourceRange R = OrigD->getSourceRange();
|
2018-07-08 07:46:53 +00:00
|
|
|
entity->def.extent =
|
2018-07-25 17:36:30 +00:00
|
|
|
GetUse(db,
|
|
|
|
R.getBegin().isFileID()
|
|
|
|
? FromTokenRange(SM, Lang, OrigD->getSourceRange())
|
|
|
|
: loc,
|
|
|
|
LexDC, Role::None);
|
2018-07-07 23:56:47 +00:00
|
|
|
} else if (is_decl) {
|
|
|
|
entity->declarations.push_back(GetUse(db, loc, LexDC, role));
|
|
|
|
} else {
|
|
|
|
entity->uses.push_back(GetUse(db, loc, LexDC, role));
|
2018-07-08 19:49:27 +00:00
|
|
|
return;
|
2018-07-07 23:56:47 +00:00
|
|
|
}
|
2018-07-08 19:49:27 +00:00
|
|
|
if (entity->def.comments[0] == '\0' && g_config->index.comments)
|
|
|
|
entity->def.comments = Intern(GetComment(OrigD));
|
2018-07-07 23:56:47 +00:00
|
|
|
};
|
2018-07-06 00:53:33 +00:00
|
|
|
switch (kind) {
|
|
|
|
case SymbolKind::Invalid:
|
2018-07-08 19:49:27 +00:00
|
|
|
LOG_S(INFO) << "Unhandled " << int(D->getKind()) << " " << info->qualified
|
2018-07-16 01:26:48 +00:00
|
|
|
<< " in " << db->path << ":" << loc.start.line + 1;
|
2018-07-06 00:53:33 +00:00
|
|
|
return true;
|
|
|
|
case SymbolKind::File:
|
|
|
|
return true;
|
|
|
|
case SymbolKind::Func:
|
|
|
|
func = &db->ToFunc(usr);
|
2018-07-15 18:27:59 +00:00
|
|
|
// Span one more column to the left/right if D is CXXConstructor.
|
|
|
|
if (!is_def && !is_decl && D->getKind() == Decl::CXXConstructor)
|
|
|
|
role = Role(role | Role::Implicit);
|
2018-07-07 23:56:47 +00:00
|
|
|
do_def_decl(func);
|
2018-07-08 19:49:27 +00:00
|
|
|
if (Spell != Loc)
|
2018-07-13 02:13:01 +00:00
|
|
|
AddMacroUse(db, SM, usr, SymbolKind::Func, Spell);
|
2018-07-08 19:49:27 +00:00
|
|
|
if (func->def.detailed_name[0] == '\0')
|
|
|
|
SetName(OrigD, info->short_name, info->qualified, func->def);
|
2018-07-07 23:56:47 +00:00
|
|
|
if (is_def || is_decl) {
|
2018-07-21 06:27:47 +00:00
|
|
|
const Decl *DC = cast<Decl>(SemDC);
|
2018-07-07 23:56:47 +00:00
|
|
|
if (GetSymbolKind(DC) == SymbolKind::Type)
|
|
|
|
db->ToType(GetUsr(DC)).def.funcs.push_back(usr);
|
2018-07-21 06:27:47 +00:00
|
|
|
} else {
|
|
|
|
const Decl *DC = cast<Decl>(LexDC);
|
|
|
|
if (GetSymbolKind(DC) == SymbolKind::Func)
|
|
|
|
db->ToFunc(GetUsr(DC))
|
|
|
|
.def.callees.push_back({{loc, usr, SymbolKind::Func, role}});
|
2018-06-01 23:51:39 +00:00
|
|
|
}
|
|
|
|
break;
|
2018-07-06 00:53:33 +00:00
|
|
|
case SymbolKind::Type:
|
|
|
|
type = &db->ToType(usr);
|
2018-07-07 23:56:47 +00:00
|
|
|
do_def_decl(type);
|
2018-07-08 19:49:27 +00:00
|
|
|
if (Spell != Loc)
|
2018-07-13 02:13:01 +00:00
|
|
|
AddMacroUse(db, SM, usr, SymbolKind::Type, Spell);
|
2018-07-08 19:49:27 +00:00
|
|
|
if (type->def.detailed_name[0] == '\0')
|
|
|
|
SetName(OrigD, info->short_name, info->qualified, type->def);
|
2018-07-07 23:56:47 +00:00
|
|
|
if (is_def || is_decl) {
|
2018-08-09 17:08:14 +00:00
|
|
|
const Decl *DC = cast<Decl>(SemDC);
|
2018-07-07 23:56:47 +00:00
|
|
|
if (GetSymbolKind(DC) == SymbolKind::Type)
|
|
|
|
db->ToType(GetUsr(DC)).def.types.push_back(usr);
|
2018-06-01 23:51:39 +00:00
|
|
|
}
|
2018-07-06 00:53:33 +00:00
|
|
|
break;
|
|
|
|
case SymbolKind::Var:
|
|
|
|
var = &db->ToVar(usr);
|
2018-07-07 23:56:47 +00:00
|
|
|
do_def_decl(var);
|
2018-07-08 19:49:27 +00:00
|
|
|
if (Spell != Loc)
|
2018-07-13 02:13:01 +00:00
|
|
|
AddMacroUse(db, SM, usr, SymbolKind::Var, Spell);
|
2018-07-08 19:49:27 +00:00
|
|
|
if (var->def.detailed_name[0] == '\0')
|
|
|
|
SetVarName(OrigD, info->short_name, info->qualified, var->def);
|
|
|
|
QualType T;
|
|
|
|
if (auto *VD = dyn_cast<VarDecl>(D))
|
|
|
|
T = VD->getType();
|
|
|
|
else if (auto *FD = dyn_cast<FieldDecl>(D))
|
|
|
|
T = FD->getType();
|
2018-07-07 23:56:47 +00:00
|
|
|
if (is_def || is_decl) {
|
2018-07-21 06:27:47 +00:00
|
|
|
const Decl *DC = cast<Decl>(SemDC);
|
2018-07-08 19:49:27 +00:00
|
|
|
if (GetSymbolKind(DC) == SymbolKind::Func)
|
2018-07-07 23:56:47 +00:00
|
|
|
db->ToFunc(GetUsr(DC)).def.vars.push_back(usr);
|
|
|
|
else if (auto *ND = dyn_cast<NamespaceDecl>(SemDC))
|
|
|
|
db->ToType(GetUsr(ND)).def.vars.emplace_back(usr, -1);
|
|
|
|
if (!T.isNull()) {
|
|
|
|
if (auto *BT = T->getAs<BuiltinType>()) {
|
|
|
|
Usr usr1 = static_cast<Usr>(BT->getKind());
|
|
|
|
var->def.type = usr1;
|
|
|
|
db->ToType(usr1).instances.push_back(usr);
|
|
|
|
} else {
|
|
|
|
for (const Decl *D1 = GetTypeDecl(T); D1; D1 = GetSpecialized(D1)) {
|
2018-08-09 17:08:14 +00:00
|
|
|
IndexParam::DeclInfo *info1;
|
2018-07-08 19:49:27 +00:00
|
|
|
Usr usr1 = GetUsr(D1, &info1);
|
2018-07-07 23:56:47 +00:00
|
|
|
auto it = db->usr2type.find(usr1);
|
|
|
|
if (it != db->usr2type.end()) {
|
|
|
|
var->def.type = usr1;
|
|
|
|
it->second.instances.push_back(usr);
|
|
|
|
break;
|
|
|
|
}
|
2018-08-09 17:08:14 +00:00
|
|
|
// e.g. TemplateTypeParmDecl is not handled by
|
|
|
|
// handleDeclOccurence.
|
2018-07-08 19:49:27 +00:00
|
|
|
SourceRange R1 = D1->getSourceRange();
|
|
|
|
if (SM.getFileID(R1.getBegin()) == LocFID) {
|
2018-08-09 17:08:14 +00:00
|
|
|
IndexType &type1 = db->ToType(usr1);
|
2018-07-10 06:40:26 +00:00
|
|
|
SourceLocation L1 = D1->getLocation();
|
|
|
|
type1.def.spell = GetUse(db, FromTokenRange(SM, Lang, {L1, L1}),
|
|
|
|
SemDC, Role::Definition);
|
|
|
|
type1.def.extent =
|
|
|
|
GetUse(db, FromTokenRange(SM, Lang, R1), LexDC, Role::None);
|
2018-07-08 19:49:27 +00:00
|
|
|
type1.def.detailed_name = Intern(info1->short_name);
|
|
|
|
type1.def.short_name_size = int16_t(info1->short_name.size());
|
|
|
|
type1.def.kind = lsSymbolKind::TypeParameter;
|
|
|
|
var->def.type = usr1;
|
|
|
|
type1.instances.push_back(usr);
|
|
|
|
break;
|
|
|
|
}
|
2018-07-07 23:56:47 +00:00
|
|
|
}
|
2018-07-06 00:53:33 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-08 19:49:27 +00:00
|
|
|
} else if (!var->def.spell && var->declarations.empty()) {
|
|
|
|
// e.g. lambda parameter
|
|
|
|
SourceLocation L = OrigD->getLocation();
|
|
|
|
if (SM.getFileID(L) == LocFID) {
|
|
|
|
var->def.spell = GetUse(db, FromTokenRange(SM, Lang, {L, L}), SemDC,
|
|
|
|
Role::Definition);
|
|
|
|
var->def.extent =
|
|
|
|
GetUse(db, FromTokenRange(SM, Lang, OrigD->getSourceRange()),
|
|
|
|
LexDC, Role::None);
|
|
|
|
}
|
2018-07-07 23:56:47 +00:00
|
|
|
}
|
2018-07-06 00:53:33 +00:00
|
|
|
break;
|
2018-06-01 23:51:39 +00:00
|
|
|
}
|
2018-01-03 06:52:35 +00:00
|
|
|
|
2018-07-06 00:53:33 +00:00
|
|
|
switch (D->getKind()) {
|
|
|
|
case Decl::Namespace:
|
|
|
|
type->def.kind = lsSymbolKind::Namespace;
|
2018-07-17 06:22:34 +00:00
|
|
|
if (OrigD->isFirstDecl()) {
|
|
|
|
auto *ND = cast<NamespaceDecl>(OrigD);
|
|
|
|
auto *ND1 = cast<Decl>(ND->getParent());
|
|
|
|
if (isa<NamespaceDecl>(ND1)) {
|
|
|
|
Usr usr1 = GetUsr(ND1);
|
|
|
|
type->def.bases.push_back(usr1);
|
|
|
|
db->ToType(usr1).derived.push_back(usr);
|
|
|
|
}
|
|
|
|
}
|
2018-07-06 00:53:33 +00:00
|
|
|
break;
|
|
|
|
case Decl::NamespaceAlias: {
|
|
|
|
type->def.kind = lsSymbolKind::TypeAlias;
|
2018-07-17 06:22:34 +00:00
|
|
|
auto *NAD = cast<NamespaceAliasDecl>(D);
|
|
|
|
if (const NamespaceDecl *ND = NAD->getNamespace()) {
|
2018-07-06 00:53:33 +00:00
|
|
|
Usr usr1 = GetUsr(ND);
|
2018-07-17 06:22:34 +00:00
|
|
|
type->def.alias_of = usr1;
|
|
|
|
(void)db->ToType(usr1);
|
2018-07-06 00:53:33 +00:00
|
|
|
}
|
2018-02-10 20:53:18 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-07-09 07:05:56 +00:00
|
|
|
case Decl::ObjCCategory:
|
|
|
|
case Decl::ObjCImplementation:
|
|
|
|
case Decl::ObjCInterface:
|
|
|
|
case Decl::ObjCProtocol:
|
|
|
|
type->def.kind = lsSymbolKind::Interface;
|
|
|
|
break;
|
|
|
|
case Decl::ObjCMethod:
|
|
|
|
func->def.kind = lsSymbolKind::Method;
|
|
|
|
break;
|
|
|
|
case Decl::ObjCProperty:
|
|
|
|
var->def.kind = lsSymbolKind::Property;
|
|
|
|
break;
|
|
|
|
case Decl::ClassTemplate:
|
|
|
|
type->def.kind = lsSymbolKind::Class;
|
|
|
|
break;
|
|
|
|
case Decl::FunctionTemplate:
|
|
|
|
func->def.kind = lsSymbolKind::Function;
|
|
|
|
break;
|
|
|
|
case Decl::TypeAliasTemplate:
|
|
|
|
type->def.kind = lsSymbolKind::TypeAlias;
|
|
|
|
break;
|
|
|
|
case Decl::VarTemplate:
|
|
|
|
var->def.kind = lsSymbolKind::Variable;
|
|
|
|
break;
|
|
|
|
case Decl::TemplateTemplateParm:
|
|
|
|
type->def.kind = lsSymbolKind::TypeParameter;
|
|
|
|
break;
|
2018-07-06 00:53:33 +00:00
|
|
|
case Decl::Enum:
|
|
|
|
type->def.kind = lsSymbolKind::Enum;
|
|
|
|
break;
|
2018-07-15 18:27:59 +00:00
|
|
|
case Decl::CXXRecord:
|
|
|
|
if (is_def) {
|
|
|
|
auto *RD = dyn_cast<CXXRecordDecl>(OrigD);
|
|
|
|
if (RD && RD->hasDefinition()) {
|
|
|
|
for (const CXXBaseSpecifier &Base : RD->bases()) {
|
|
|
|
QualType T = Base.getType();
|
|
|
|
const NamedDecl *BaseD = nullptr;
|
|
|
|
if (auto *TDT = T->getAs<TypedefType>()) {
|
|
|
|
BaseD = TDT->getDecl();
|
|
|
|
} else if (auto *TST = T->getAs<TemplateSpecializationType>()) {
|
|
|
|
BaseD = TST->getTemplateName().getAsTemplateDecl();
|
|
|
|
} else if (auto *RT = T->getAs<RecordType>()) {
|
|
|
|
BaseD = RT->getDecl();
|
|
|
|
}
|
|
|
|
if (BaseD) {
|
|
|
|
Usr usr1 = GetUsr(BaseD);
|
2018-07-17 06:22:34 +00:00
|
|
|
type->def.bases.push_back(usr1);
|
|
|
|
db->ToType(usr1).derived.push_back(usr);
|
2018-07-07 23:56:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[[fallthrough]];
|
2018-07-15 18:27:59 +00:00
|
|
|
case Decl::Record:
|
|
|
|
if (auto *RD = dyn_cast<RecordDecl>(OrigD)) {
|
|
|
|
// spec has no Union, use Class
|
|
|
|
type->def.kind = RD->getTagKind() == TTK_Struct ? lsSymbolKind::Struct
|
|
|
|
: lsSymbolKind::Class;
|
|
|
|
if (is_def) {
|
2018-07-23 03:10:04 +00:00
|
|
|
SmallVector<std::pair<const RecordDecl *, int>, 2> Stack{{RD, 0}};
|
2018-08-03 23:11:32 +00:00
|
|
|
llvm::DenseSet<const RecordDecl *> Seen;
|
|
|
|
Seen.insert(RD);
|
2018-07-23 03:10:04 +00:00
|
|
|
while (Stack.size()) {
|
|
|
|
int offset;
|
|
|
|
std::tie(RD, offset) = Stack.back();
|
|
|
|
Stack.pop_back();
|
2018-08-03 23:11:32 +00:00
|
|
|
if (!RD->isCompleteDefinition() || RD->isDependentType() ||
|
|
|
|
!ValidateRecord(RD))
|
2018-07-23 03:10:04 +00:00
|
|
|
offset = -1;
|
|
|
|
for (FieldDecl *FD : RD->fields()) {
|
|
|
|
int offset1 = offset >= 0 ? offset + Ctx->getFieldOffset(FD) : -1;
|
|
|
|
if (FD->getIdentifier())
|
|
|
|
type->def.vars.emplace_back(GetUsr(FD), offset1);
|
2018-08-03 23:11:32 +00:00
|
|
|
else if (const auto *RT1 = FD->getType()->getAs<RecordType>()) {
|
|
|
|
if (const RecordDecl *RD1 = RT1->getDecl())
|
|
|
|
if (Seen.insert(RD1).second)
|
|
|
|
Stack.push_back({RD1, offset1});
|
|
|
|
}
|
2018-07-23 03:10:04 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-15 18:27:59 +00:00
|
|
|
}
|
2018-07-06 00:53:33 +00:00
|
|
|
}
|
|
|
|
break;
|
2018-07-07 23:56:47 +00:00
|
|
|
case Decl::ClassTemplateSpecialization:
|
2018-07-08 19:49:27 +00:00
|
|
|
case Decl::ClassTemplatePartialSpecialization:
|
2018-07-07 23:56:47 +00:00
|
|
|
type->def.kind = lsSymbolKind::Class;
|
|
|
|
if (is_def || is_decl) {
|
|
|
|
if (auto *RD = dyn_cast<CXXRecordDecl>(D)) {
|
|
|
|
Decl *D1 = nullptr;
|
|
|
|
if (auto *SD = dyn_cast<ClassTemplatePartialSpecializationDecl>(RD))
|
|
|
|
D1 = SD->getSpecializedTemplate();
|
|
|
|
else if (auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
|
|
|
|
llvm::PointerUnion<ClassTemplateDecl *,
|
|
|
|
ClassTemplatePartialSpecializationDecl *>
|
|
|
|
Result = SD->getSpecializedTemplateOrPartial();
|
|
|
|
if (Result.is<ClassTemplateDecl *>())
|
|
|
|
D1 = Result.get<ClassTemplateDecl *>();
|
|
|
|
else
|
|
|
|
D1 = Result.get<ClassTemplatePartialSpecializationDecl *>();
|
|
|
|
|
|
|
|
} else
|
|
|
|
D1 = RD->getInstantiatedFromMemberClass();
|
|
|
|
if (D1) {
|
|
|
|
Usr usr1 = GetUsr(D1);
|
2018-07-17 06:22:34 +00:00
|
|
|
type->def.bases.push_back(usr1);
|
|
|
|
db->ToType(usr1).derived.push_back(usr);
|
2018-07-07 23:56:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2018-07-06 00:53:33 +00:00
|
|
|
case Decl::TypeAlias:
|
|
|
|
case Decl::Typedef:
|
|
|
|
case Decl::UnresolvedUsingTypename:
|
|
|
|
type->def.kind = lsSymbolKind::TypeAlias;
|
|
|
|
if (auto *TD = dyn_cast<TypedefNameDecl>(D)) {
|
2018-07-23 03:10:04 +00:00
|
|
|
bool specialization = false;
|
2018-07-06 00:53:33 +00:00
|
|
|
QualType T = TD->getUnderlyingType();
|
2018-07-23 03:10:04 +00:00
|
|
|
if (const Decl *D1 = GetTypeDecl(T, &specialization)) {
|
2018-07-06 00:53:33 +00:00
|
|
|
Usr usr1 = GetUsr(D1);
|
2018-07-23 03:10:04 +00:00
|
|
|
IndexType &type1 = db->ToType(usr1);
|
|
|
|
type->def.alias_of = usr1;
|
|
|
|
// Not visited template<class T> struct B {typedef A<T> t;};
|
|
|
|
if (specialization) {
|
|
|
|
const TypeSourceInfo *TSI = TD->getTypeSourceInfo();
|
|
|
|
SourceLocation L1 = TSI->getTypeLoc().getBeginLoc();
|
2018-07-27 07:21:57 +00:00
|
|
|
if (SM.getFileID(L1) == LocFID) {
|
|
|
|
Range loc1 = FromTokenRange(SM, Lang, {L1, L1});
|
|
|
|
type1.uses.push_back(GetUse(db, loc1, LexDC, Role::Reference));
|
|
|
|
}
|
2018-07-23 03:10:04 +00:00
|
|
|
}
|
2018-07-06 00:53:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2018-07-08 19:49:27 +00:00
|
|
|
case Decl::Binding:
|
|
|
|
var->def.kind = lsSymbolKind::Variable;
|
2018-07-09 07:05:56 +00:00
|
|
|
break;
|
2018-07-08 19:49:27 +00:00
|
|
|
case Decl::Field:
|
2018-07-09 07:05:56 +00:00
|
|
|
case Decl::ObjCIvar:
|
2018-07-08 19:49:27 +00:00
|
|
|
var->def.kind = lsSymbolKind::Field;
|
|
|
|
break;
|
2018-07-06 00:53:33 +00:00
|
|
|
case Decl::Function:
|
|
|
|
func->def.kind = lsSymbolKind::Function;
|
|
|
|
break;
|
2018-07-21 06:27:47 +00:00
|
|
|
case Decl::CXXMethod: {
|
|
|
|
const auto *MD = cast<CXXMethodDecl>(D);
|
|
|
|
func->def.kind =
|
|
|
|
MD->isStatic() ? lsSymbolKind::StaticMethod : lsSymbolKind::Method;
|
2018-07-07 23:56:47 +00:00
|
|
|
if (is_def || is_decl) {
|
|
|
|
if (auto *ND = dyn_cast<NamedDecl>(D)) {
|
|
|
|
SmallVector<const NamedDecl *, 8> OverDecls;
|
|
|
|
Ctx->getOverriddenMethods(ND, OverDecls);
|
2018-08-09 17:08:14 +00:00
|
|
|
for (const auto *ND1 : OverDecls) {
|
2018-07-07 23:56:47 +00:00
|
|
|
Usr usr1 = GetUsr(ND1);
|
2018-07-17 06:22:34 +00:00
|
|
|
func->def.bases.push_back(usr1);
|
|
|
|
db->ToFunc(usr1).derived.push_back(usr);
|
2018-07-07 23:56:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-07-06 00:53:33 +00:00
|
|
|
break;
|
2018-07-21 06:27:47 +00:00
|
|
|
}
|
2018-07-06 00:53:33 +00:00
|
|
|
case Decl::CXXConstructor:
|
|
|
|
case Decl::CXXConversion:
|
|
|
|
func->def.kind = lsSymbolKind::Constructor;
|
|
|
|
break;
|
|
|
|
case Decl::CXXDestructor:
|
|
|
|
func->def.kind = lsSymbolKind::Method;
|
|
|
|
break;
|
|
|
|
case Decl::Var:
|
2018-07-07 23:56:47 +00:00
|
|
|
case Decl::Decomposition:
|
2018-07-06 00:53:33 +00:00
|
|
|
var->def.kind = lsSymbolKind::Variable;
|
2018-07-07 23:56:47 +00:00
|
|
|
break;
|
2018-07-06 00:53:33 +00:00
|
|
|
case Decl::ImplicitParam:
|
2018-07-07 23:56:47 +00:00
|
|
|
case Decl::ParmVar:
|
|
|
|
// ccls extension
|
|
|
|
var->def.kind = lsSymbolKind::Parameter;
|
2018-07-06 00:53:33 +00:00
|
|
|
break;
|
2018-07-16 01:26:48 +00:00
|
|
|
case Decl::VarTemplateSpecialization:
|
|
|
|
case Decl::VarTemplatePartialSpecialization:
|
|
|
|
var->def.kind = lsSymbolKind::Variable;
|
|
|
|
break;
|
2018-07-07 23:56:47 +00:00
|
|
|
case Decl::EnumConstant:
|
|
|
|
var->def.kind = lsSymbolKind::EnumMember;
|
2018-07-08 07:46:53 +00:00
|
|
|
// TODO Pretty printer may print =
|
|
|
|
if (is_def && strchr(var->def.detailed_name, '=') == nullptr) {
|
2018-07-07 23:56:47 +00:00
|
|
|
auto *ECD = cast<EnumConstantDecl>(D);
|
|
|
|
const auto &Val = ECD->getInitVal();
|
|
|
|
std::string init =
|
|
|
|
" = " + (Val.isSigned() ? std::to_string(Val.getSExtValue())
|
|
|
|
: std::to_string(Val.getZExtValue()));
|
|
|
|
var->def.hover = Intern(var->def.detailed_name + init);
|
|
|
|
}
|
2018-02-10 20:53:18 +00:00
|
|
|
break;
|
2018-07-08 19:49:27 +00:00
|
|
|
case Decl::UnresolvedUsingValue:
|
|
|
|
var->def.kind = lsSymbolKind::Variable;
|
|
|
|
break;
|
2018-07-06 00:53:33 +00:00
|
|
|
default:
|
|
|
|
LOG_S(INFO) << "Unhandled " << int(D->getKind());
|
2018-02-10 20:53:18 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-07-06 00:53:33 +00:00
|
|
|
return true;
|
2017-12-24 08:35:38 +00:00
|
|
|
}
|
2018-07-06 00:53:33 +00:00
|
|
|
};
|
2018-07-07 23:56:47 +00:00
|
|
|
|
|
|
|
class IndexPPCallbacks : public PPCallbacks {
|
2018-08-09 17:08:14 +00:00
|
|
|
SourceManager &SM;
|
|
|
|
IndexParam ¶m;
|
2018-07-07 23:56:47 +00:00
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
std::pair<StringRef, Usr> GetMacro(const Token &Tok) const {
|
2018-07-07 23:56:47 +00:00
|
|
|
StringRef Name = Tok.getIdentifierInfo()->getName();
|
|
|
|
SmallString<256> USR("@macro@");
|
|
|
|
USR += Name;
|
|
|
|
return {Name, HashUsr(USR)};
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2018-07-08 19:49:27 +00:00
|
|
|
IndexPPCallbacks(SourceManager &SM, IndexParam ¶m)
|
|
|
|
: SM(SM), param(param) {}
|
2018-07-08 07:46:53 +00:00
|
|
|
void InclusionDirective(SourceLocation HashLoc, const Token &Tok,
|
|
|
|
StringRef Included, bool IsAngled,
|
|
|
|
CharSourceRange FilenameRange, const FileEntry *File,
|
|
|
|
StringRef SearchPath, StringRef RelativePath,
|
2018-07-08 19:49:27 +00:00
|
|
|
const Module *Imported
|
|
|
|
#if LLVM_VERSION_MAJOR >= 7
|
|
|
|
,
|
|
|
|
SrcMgr::CharacteristicKind FileType
|
|
|
|
#endif
|
|
|
|
) override {
|
2018-07-08 07:46:53 +00:00
|
|
|
if (!File)
|
|
|
|
return;
|
|
|
|
llvm::sys::fs::UniqueID UniqueID;
|
2018-07-29 04:32:41 +00:00
|
|
|
auto spell = FromCharSourceRange(SM, param.Ctx->getLangOpts(),
|
|
|
|
FilenameRange, &UniqueID);
|
|
|
|
const FileEntry *FE =
|
|
|
|
SM.getFileEntryForID(SM.getFileID(FilenameRange.getBegin()));
|
2018-07-08 07:46:53 +00:00
|
|
|
if (!FE)
|
|
|
|
return;
|
|
|
|
if (IndexFile *db = param.ConsumeFile(*FE)) {
|
|
|
|
std::string file_name = FileName(*File);
|
|
|
|
if (file_name.size())
|
|
|
|
db->includes.push_back({spell.start.line, std::move(file_name)});
|
|
|
|
}
|
|
|
|
}
|
2018-07-07 23:56:47 +00:00
|
|
|
void MacroDefined(const Token &Tok, const MacroDirective *MD) override {
|
|
|
|
llvm::sys::fs::UniqueID UniqueID;
|
2018-08-09 17:08:14 +00:00
|
|
|
const LangOptions &Lang = param.Ctx->getLangOpts();
|
2018-07-07 23:56:47 +00:00
|
|
|
SourceLocation L = MD->getLocation();
|
|
|
|
const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(L));
|
|
|
|
if (!FE)
|
|
|
|
return;
|
|
|
|
if (IndexFile *db = param.ConsumeFile(*FE)) {
|
2018-08-09 17:08:14 +00:00
|
|
|
auto [Name, usr] = GetMacro(Tok);
|
2018-07-07 23:56:47 +00:00
|
|
|
IndexVar &var = db->ToVar(usr);
|
2018-07-08 19:49:27 +00:00
|
|
|
auto range = FromTokenRange(SM, Lang, {L, L}, &UniqueID);
|
|
|
|
var.def.kind = lsSymbolKind::Macro;
|
|
|
|
if (var.def.spell)
|
|
|
|
var.declarations.push_back(*var.def.spell);
|
|
|
|
var.def.spell = Use{{range, 0, SymbolKind::File, Role::Definition}};
|
|
|
|
const MacroInfo *MI = MD->getMacroInfo();
|
|
|
|
SourceRange R(MI->getDefinitionLoc(), MI->getDefinitionEndLoc());
|
|
|
|
range = FromTokenRange(SM, param.Ctx->getLangOpts(), R);
|
|
|
|
var.def.extent = Use{{range, 0, SymbolKind::File, Role::None}};
|
|
|
|
if (var.def.detailed_name[0] == '\0') {
|
2018-07-07 23:56:47 +00:00
|
|
|
var.def.detailed_name = Intern(Name);
|
|
|
|
var.def.short_name_size = Name.size();
|
2018-07-15 18:27:59 +00:00
|
|
|
StringRef Buf = GetSourceInRange(SM, Lang, R);
|
|
|
|
var.def.hover =
|
|
|
|
Intern(Buf.count('\n') <= kInitializerMaxLines - 1
|
|
|
|
? Twine("#define ", GetSourceInRange(SM, Lang, R)).str()
|
|
|
|
: Twine("#define ", Name).str());
|
2018-07-07 23:56:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-08-09 17:08:14 +00:00
|
|
|
void MacroExpands(const Token &Tok, const MacroDefinition &MD, SourceRange R,
|
|
|
|
const MacroArgs *Args) override {
|
2018-07-07 23:56:47 +00:00
|
|
|
llvm::sys::fs::UniqueID UniqueID;
|
2018-07-13 02:13:01 +00:00
|
|
|
SourceLocation L = SM.getSpellingLoc(R.getBegin());
|
|
|
|
const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(L));
|
2018-07-07 23:56:47 +00:00
|
|
|
if (!FE)
|
|
|
|
return;
|
|
|
|
if (IndexFile *db = param.ConsumeFile(*FE)) {
|
2018-08-09 17:08:14 +00:00
|
|
|
auto [Name, usr] = GetMacro(Tok);
|
2018-07-07 23:56:47 +00:00
|
|
|
IndexVar &var = db->ToVar(usr);
|
2018-07-13 02:13:01 +00:00
|
|
|
var.uses.push_back(
|
|
|
|
{{FromTokenRange(SM, param.Ctx->getLangOpts(), {L, L}, &UniqueID), 0,
|
|
|
|
SymbolKind::File, Role::Dynamic}});
|
2018-07-07 23:56:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
void MacroUndefined(const Token &Tok, const MacroDefinition &MD,
|
|
|
|
const MacroDirective *UD) override {
|
2018-07-08 07:46:53 +00:00
|
|
|
if (UD) {
|
|
|
|
SourceLocation L = UD->getLocation();
|
|
|
|
MacroExpands(Tok, MD, {L, L}, nullptr);
|
|
|
|
}
|
2018-07-07 23:56:47 +00:00
|
|
|
}
|
|
|
|
void SourceRangeSkipped(SourceRange Range, SourceLocation EndifLoc) override {
|
|
|
|
llvm::sys::fs::UniqueID UniqueID;
|
|
|
|
auto range = FromCharRange(SM, param.Ctx->getLangOpts(), Range, &UniqueID);
|
|
|
|
const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Range.getBegin()));
|
|
|
|
if (IndexFile *db = param.ConsumeFile(*FE))
|
|
|
|
db->skipped_ranges.push_back(range);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class IndexFrontendAction : public ASTFrontendAction {
|
2018-08-09 17:08:14 +00:00
|
|
|
IndexParam ¶m;
|
|
|
|
|
2018-07-07 23:56:47 +00:00
|
|
|
public:
|
2018-08-09 17:08:14 +00:00
|
|
|
IndexFrontendAction(IndexParam ¶m) : param(param) {}
|
2018-07-07 23:56:47 +00:00
|
|
|
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
|
|
|
|
StringRef InFile) override {
|
|
|
|
Preprocessor &PP = CI.getPreprocessor();
|
2018-08-09 17:08:14 +00:00
|
|
|
PP.addPPCallbacks(
|
|
|
|
std::make_unique<IndexPPCallbacks>(PP.getSourceManager(), param));
|
2018-07-07 23:56:47 +00:00
|
|
|
return std::make_unique<ASTConsumer>();
|
|
|
|
}
|
|
|
|
};
|
2018-08-09 17:08:14 +00:00
|
|
|
} // namespace
|
2017-12-24 08:35:38 +00:00
|
|
|
|
2018-07-13 02:13:01 +00:00
|
|
|
const int IndexFile::kMajorVersion = 17;
|
2018-07-15 18:27:59 +00:00
|
|
|
const int IndexFile::kMinorVersion = 1;
|
2017-05-20 21:45:46 +00:00
|
|
|
|
2018-07-07 23:56:47 +00:00
|
|
|
IndexFile::IndexFile(llvm::sys::fs::UniqueID UniqueID, const std::string &path,
|
2018-07-06 00:53:33 +00:00
|
|
|
const std::string &contents)
|
2018-07-07 23:56:47 +00:00
|
|
|
: UniqueID(UniqueID), path(path), file_contents(contents) {}
|
2017-02-20 00:56:56 +00:00
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
IndexFunc &IndexFile::ToFunc(Usr usr) {
|
2018-07-10 06:40:26 +00:00
|
|
|
auto [it, inserted] = usr2func.try_emplace(usr);
|
|
|
|
if (inserted)
|
|
|
|
it->second.usr = usr;
|
|
|
|
return it->second;
|
2017-02-20 00:56:56 +00:00
|
|
|
}
|
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
IndexType &IndexFile::ToType(Usr usr) {
|
2018-07-10 06:40:26 +00:00
|
|
|
auto [it, inserted] = usr2type.try_emplace(usr);
|
|
|
|
if (inserted)
|
|
|
|
it->second.usr = usr;
|
|
|
|
return it->second;
|
2017-02-20 00:56:56 +00:00
|
|
|
}
|
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
IndexVar &IndexFile::ToVar(Usr usr) {
|
2018-07-10 06:40:26 +00:00
|
|
|
auto [it, inserted] = usr2var.try_emplace(usr);
|
|
|
|
if (inserted)
|
|
|
|
it->second.usr = usr;
|
|
|
|
return it->second;
|
2017-02-17 09:57:44 +00:00
|
|
|
}
|
|
|
|
|
2017-05-12 06:08:15 +00:00
|
|
|
std::string IndexFile::ToString() {
|
2018-06-08 04:53:41 +00:00
|
|
|
return ccls::Serialize(SerializeFormat::Json, *this);
|
2017-02-17 09:57:44 +00:00
|
|
|
}
|
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
template <typename T> void Uniquify(std::vector<T> &a) {
|
2018-07-17 06:22:34 +00:00
|
|
|
std::unordered_set<T> seen;
|
2018-02-23 18:14:54 +00:00
|
|
|
size_t n = 0;
|
2018-07-17 06:22:34 +00:00
|
|
|
for (size_t i = 0; i < a.size(); i++)
|
|
|
|
if (seen.insert(a[i]).second)
|
|
|
|
a[n++] = a[i];
|
|
|
|
a.resize(n);
|
2017-02-24 08:39:25 +00:00
|
|
|
}
|
2017-02-20 06:40:55 +00:00
|
|
|
|
2018-07-08 07:46:53 +00:00
|
|
|
namespace ccls::idx {
|
2018-08-09 17:08:14 +00:00
|
|
|
std::vector<std::unique_ptr<IndexFile>>
|
|
|
|
Index(VFS *vfs, const std::string &opt_wdir, const std::string &file,
|
|
|
|
const std::vector<std::string> &args,
|
|
|
|
const std::vector<FileContents> &file_contents) {
|
2018-04-04 06:05:41 +00:00
|
|
|
if (!g_config->index.enabled)
|
2018-04-02 07:22:12 +00:00
|
|
|
return {};
|
2017-04-19 00:05:14 +00:00
|
|
|
|
2018-07-06 00:53:33 +00:00
|
|
|
std::vector<const char *> Args;
|
2018-08-09 17:08:14 +00:00
|
|
|
for (auto &arg : args)
|
2018-07-06 00:53:33 +00:00
|
|
|
Args.push_back(arg.c_str());
|
|
|
|
auto PCHCO = std::make_shared<PCHContainerOperations>();
|
2018-08-09 17:08:14 +00:00
|
|
|
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
|
|
|
|
CompilerInstance::createDiagnostics(new DiagnosticOptions));
|
2018-07-06 00:53:33 +00:00
|
|
|
std::shared_ptr<CompilerInvocation> CI =
|
|
|
|
createInvocationFromCommandLine(Args, Diags);
|
|
|
|
if (!CI)
|
|
|
|
return {};
|
2018-07-08 07:46:53 +00:00
|
|
|
// -fparse-all-comments enables documentation in the indexer and in
|
|
|
|
// code completion.
|
|
|
|
if (g_config->index.comments > 1)
|
|
|
|
CI->getLangOpts()->CommentOpts.ParseAllComments = true;
|
|
|
|
CI->getLangOpts()->SpellChecking = false;
|
|
|
|
{
|
|
|
|
// FileSystemOptions& FSOpts = CI->getFileSystemOpts();
|
|
|
|
// if (FSOpts.WorkingDir.empty())
|
|
|
|
// FSOpts.WorkingDir = opt_wdir;
|
|
|
|
// HeaderSearchOptions &HSOpts = CI->getHeaderSearchOpts();
|
|
|
|
// llvm::errs() << HSOpts.ResourceDir << "\n";
|
|
|
|
// // lib/clang/7.0.0 is incorrect
|
|
|
|
// if (HSOpts.ResourceDir.compare(0, 3, "lib") == 0 &&
|
|
|
|
// HSOpts.UseBuiltinIncludes)
|
|
|
|
// HSOpts.ResourceDir = g_config->clang.resourceDir;
|
|
|
|
}
|
2017-05-17 07:08:45 +00:00
|
|
|
|
2018-07-06 00:53:33 +00:00
|
|
|
std::vector<std::unique_ptr<llvm::MemoryBuffer>> BufOwner;
|
|
|
|
for (auto &c : file_contents) {
|
|
|
|
std::unique_ptr<llvm::MemoryBuffer> MB =
|
|
|
|
llvm::MemoryBuffer::getMemBufferCopy(c.content, c.path);
|
|
|
|
CI->getPreprocessorOpts().addRemappedFile(c.path, MB.get());
|
|
|
|
BufOwner.push_back(std::move(MB));
|
2017-05-16 07:38:15 +00:00
|
|
|
}
|
2017-07-30 04:24:02 +00:00
|
|
|
|
2018-07-06 00:53:33 +00:00
|
|
|
auto Unit = ASTUnit::create(CI, Diags, true, true);
|
|
|
|
if (!Unit)
|
2018-04-02 07:22:12 +00:00
|
|
|
return {};
|
2017-02-16 09:35:30 +00:00
|
|
|
|
2018-05-05 22:29:17 +00:00
|
|
|
FileConsumer file_consumer(vfs, file);
|
2018-07-06 00:53:33 +00:00
|
|
|
IndexParam param(*Unit, &file_consumer);
|
|
|
|
auto DataConsumer = std::make_shared<IndexDataConsumer>(param);
|
|
|
|
|
|
|
|
index::IndexingOptions IndexOpts;
|
|
|
|
IndexOpts.SystemSymbolFilter =
|
|
|
|
index::IndexingOptions::SystemSymbolFilterKind::All;
|
|
|
|
IndexOpts.IndexFunctionLocals = true;
|
2018-07-10 06:40:26 +00:00
|
|
|
#if LLVM_VERSION_MAJOR >= 7
|
|
|
|
IndexOpts.IndexImplicitInstantiation = true;
|
|
|
|
#endif
|
2018-07-06 00:53:33 +00:00
|
|
|
|
2018-07-07 23:56:47 +00:00
|
|
|
std::unique_ptr<FrontendAction> IndexAction = createIndexingAction(
|
|
|
|
DataConsumer, IndexOpts, std::make_unique<IndexFrontendAction>(param));
|
2018-07-06 00:53:33 +00:00
|
|
|
|
|
|
|
DiagnosticErrorTrap DiagTrap(*Diags);
|
2018-07-08 07:46:53 +00:00
|
|
|
llvm::CrashRecoveryContext CRC;
|
2018-07-14 23:02:59 +00:00
|
|
|
auto compile = [&]() {
|
|
|
|
ASTUnit::LoadFromCompilerInvocationAction(
|
|
|
|
std::move(CI), PCHCO, Diags, IndexAction.get(), Unit.get(),
|
|
|
|
/*Persistent=*/true, /*ResourceDir=*/"",
|
|
|
|
/*OnlyLocalDecls=*/true,
|
2018-07-15 17:10:24 +00:00
|
|
|
/*CaptureDiagnostics=*/true, 0, false, false,
|
|
|
|
/*UserFilesAreVolatile=*/true);
|
2018-07-14 23:02:59 +00:00
|
|
|
};
|
2018-07-16 05:49:32 +00:00
|
|
|
if (!CRC.RunSafely(compile)) {
|
2018-07-14 23:02:59 +00:00
|
|
|
LOG_S(ERROR) << "clang crashed for " << file;
|
|
|
|
return {};
|
2018-07-08 07:46:53 +00:00
|
|
|
}
|
2018-07-06 00:53:33 +00:00
|
|
|
if (!Unit) {
|
|
|
|
LOG_S(ERROR) << "failed to index " << file;
|
2018-04-02 07:22:12 +00:00
|
|
|
return {};
|
2017-12-01 17:57:03 +00:00
|
|
|
}
|
2017-05-21 01:58:54 +00:00
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
const SourceManager &SM = Unit->getSourceManager();
|
|
|
|
const FileEntry *FE = SM.getFileEntryForID(SM.getMainFileID());
|
|
|
|
IndexFile *main_file = param.ConsumeFile(*FE);
|
2018-01-06 17:28:55 +00:00
|
|
|
std::unordered_map<std::string, int> inc_to_line;
|
2018-07-08 07:46:53 +00:00
|
|
|
if (main_file)
|
2018-08-09 17:08:14 +00:00
|
|
|
for (auto &inc : main_file->includes)
|
2018-01-06 22:47:24 +00:00
|
|
|
inc_to_line[inc.resolved_path] = inc.line;
|
2018-01-06 17:28:55 +00:00
|
|
|
|
2017-04-08 22:54:36 +00:00
|
|
|
auto result = param.file_consumer->TakeLocalState();
|
2018-08-09 17:08:14 +00:00
|
|
|
for (std::unique_ptr<IndexFile> &entry : result) {
|
2017-04-24 01:01:51 +00:00
|
|
|
entry->import_file = file;
|
2017-04-21 04:06:15 +00:00
|
|
|
entry->args = args;
|
2018-07-13 02:13:01 +00:00
|
|
|
for (auto &[_, it] : entry->uid2lid_and_path)
|
|
|
|
entry->lid2path.emplace_back(it.first, std::move(it.second));
|
|
|
|
entry->uid2lid_and_path.clear();
|
2018-08-09 17:08:14 +00:00
|
|
|
for (auto &it : entry->usr2func) {
|
2018-03-07 23:08:50 +00:00
|
|
|
// e.g. declaration + out-of-line definition
|
2018-04-30 04:49:03 +00:00
|
|
|
Uniquify(it.second.derived);
|
|
|
|
Uniquify(it.second.uses);
|
2018-03-07 23:08:50 +00:00
|
|
|
}
|
2018-08-09 17:08:14 +00:00
|
|
|
for (auto &it : entry->usr2type) {
|
2018-04-30 04:49:03 +00:00
|
|
|
Uniquify(it.second.derived);
|
|
|
|
Uniquify(it.second.uses);
|
2018-02-23 18:14:54 +00:00
|
|
|
// e.g. declaration + out-of-line definition
|
2018-07-27 03:08:22 +00:00
|
|
|
Uniquify(it.second.def.bases);
|
2018-04-30 04:49:03 +00:00
|
|
|
Uniquify(it.second.def.funcs);
|
2018-02-23 18:14:54 +00:00
|
|
|
}
|
2018-08-09 17:08:14 +00:00
|
|
|
for (auto &it : entry->usr2var)
|
2018-04-30 04:49:03 +00:00
|
|
|
Uniquify(it.second.uses);
|
2018-01-06 17:28:55 +00:00
|
|
|
|
2018-07-08 07:46:53 +00:00
|
|
|
if (main_file) {
|
2018-01-06 22:47:24 +00:00
|
|
|
// If there are errors, show at least one at the include position.
|
|
|
|
auto it = inc_to_line.find(entry->path);
|
|
|
|
if (it != inc_to_line.end()) {
|
|
|
|
int line = it->second;
|
|
|
|
for (auto ls_diagnostic : entry->diagnostics_) {
|
|
|
|
if (ls_diagnostic.severity != lsDiagnosticSeverity::Error)
|
|
|
|
continue;
|
|
|
|
ls_diagnostic.range =
|
2018-04-08 00:10:54 +00:00
|
|
|
lsRange{lsPosition{line, 10}, lsPosition{line, 10}};
|
2018-07-08 07:46:53 +00:00
|
|
|
main_file->diagnostics_.push_back(ls_diagnostic);
|
2018-01-06 22:47:24 +00:00
|
|
|
break;
|
|
|
|
}
|
2018-01-06 17:28:55 +00:00
|
|
|
}
|
|
|
|
}
|
2017-07-30 04:24:02 +00:00
|
|
|
|
|
|
|
// Update file contents and modification time.
|
2018-05-05 22:29:17 +00:00
|
|
|
entry->last_write_time = param.file2write_time[entry->path];
|
2017-07-30 04:24:02 +00:00
|
|
|
|
|
|
|
// Update dependencies for the file. Do not include the file in its own
|
|
|
|
// dependency set.
|
2018-07-13 02:13:01 +00:00
|
|
|
for (auto &[_, path] : param.SeenUniqueID)
|
2018-05-05 22:29:17 +00:00
|
|
|
if (path != entry->path && path != entry->import_file)
|
|
|
|
entry->dependencies[path] = param.file2write_time[path];
|
2017-04-08 22:54:36 +00:00
|
|
|
}
|
2017-04-19 00:05:14 +00:00
|
|
|
|
2018-04-02 07:22:12 +00:00
|
|
|
return result;
|
2017-03-22 17:16:09 +00:00
|
|
|
}
|
2018-08-09 17:08:14 +00:00
|
|
|
} // namespace ccls::idx
|
2017-12-01 17:45:44 +00:00
|
|
|
|
2018-02-12 04:22:47 +00:00
|
|
|
// |SymbolRef| is serialized this way.
|
|
|
|
// |Use| also uses this though it has an extra field |file|,
|
|
|
|
// which is not used by Index* so it does not need to be serialized.
|
2018-07-13 02:13:01 +00:00
|
|
|
void Reflect(Reader &vis, Reference &v) {
|
|
|
|
if (vis.Format() == SerializeFormat::Json) {
|
|
|
|
std::string t = vis.GetString();
|
|
|
|
char *s = const_cast<char *>(t.c_str());
|
|
|
|
v.range = Range::FromString(s);
|
2018-02-10 20:53:18 +00:00
|
|
|
s = strchr(s, '|');
|
2018-07-13 02:13:01 +00:00
|
|
|
v.usr = strtoull(s + 1, &s, 10);
|
|
|
|
v.kind = static_cast<SymbolKind>(strtol(s + 1, &s, 10));
|
|
|
|
v.role = static_cast<Role>(strtol(s + 1, &s, 10));
|
2018-02-08 18:38:27 +00:00
|
|
|
} else {
|
2018-07-13 02:13:01 +00:00
|
|
|
Reflect(vis, v.range);
|
|
|
|
Reflect(vis, v.usr);
|
|
|
|
Reflect(vis, v.kind);
|
|
|
|
Reflect(vis, v.role);
|
2018-02-08 18:38:27 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-13 02:13:01 +00:00
|
|
|
void Reflect(Writer &vis, Reference &v) {
|
|
|
|
if (vis.Format() == SerializeFormat::Json) {
|
2018-04-08 06:32:35 +00:00
|
|
|
char buf[99];
|
2018-04-30 04:49:03 +00:00
|
|
|
snprintf(buf, sizeof buf, "%s|%" PRIu64 "|%d|%d",
|
2018-07-13 02:13:01 +00:00
|
|
|
v.range.ToString().c_str(), v.usr, int(v.kind), int(v.role));
|
|
|
|
std::string s(buf);
|
|
|
|
Reflect(vis, s);
|
|
|
|
} else {
|
|
|
|
Reflect(vis, v.range);
|
|
|
|
Reflect(vis, v.usr);
|
|
|
|
Reflect(vis, v.kind);
|
|
|
|
Reflect(vis, v.role);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
void Reflect(Reader &vis, Use &v) {
|
2018-07-13 02:13:01 +00:00
|
|
|
if (vis.Format() == SerializeFormat::Json) {
|
|
|
|
std::string t = vis.GetString();
|
2018-08-09 17:08:14 +00:00
|
|
|
char *s = const_cast<char *>(t.c_str());
|
2018-07-13 02:13:01 +00:00
|
|
|
v.range = Range::FromString(s);
|
|
|
|
s = strchr(s, '|');
|
|
|
|
v.usr = strtoull(s + 1, &s, 10);
|
|
|
|
v.kind = static_cast<SymbolKind>(strtol(s + 1, &s, 10));
|
|
|
|
v.role = static_cast<Role>(strtol(s + 1, &s, 10));
|
|
|
|
if (*s == '|')
|
|
|
|
v.file_id = static_cast<int>(strtol(s + 1, &s, 10));
|
|
|
|
} else {
|
2018-08-09 17:08:14 +00:00
|
|
|
Reflect(vis, static_cast<Reference &>(v));
|
2018-07-13 02:13:01 +00:00
|
|
|
Reflect(vis, v.file_id);
|
|
|
|
}
|
|
|
|
}
|
2018-08-09 17:08:14 +00:00
|
|
|
void Reflect(Writer &vis, Use &v) {
|
2018-07-13 02:13:01 +00:00
|
|
|
if (vis.Format() == SerializeFormat::Json) {
|
|
|
|
char buf[99];
|
|
|
|
if (v.file_id == -1)
|
|
|
|
snprintf(buf, sizeof buf, "%s|%" PRIu64 "|%d|%d",
|
|
|
|
v.range.ToString().c_str(), v.usr, int(v.kind), int(v.role));
|
|
|
|
else
|
|
|
|
snprintf(buf, sizeof buf, "%s|%" PRIu64 "|%d|%d|%d",
|
|
|
|
v.range.ToString().c_str(), v.usr, int(v.kind), int(v.role),
|
|
|
|
v.file_id);
|
2018-04-08 06:32:35 +00:00
|
|
|
std::string s(buf);
|
2018-07-13 02:13:01 +00:00
|
|
|
Reflect(vis, s);
|
2018-02-08 18:38:27 +00:00
|
|
|
} else {
|
2018-08-09 17:08:14 +00:00
|
|
|
Reflect(vis, static_cast<Reference &>(v));
|
2018-07-13 02:13:01 +00:00
|
|
|
Reflect(vis, v.file_id);
|
2018-02-08 18:38:27 +00:00
|
|
|
}
|
|
|
|
}
|