15 #include "clang/AST/ASTContext.h" 16 #include "clang/AST/Decl.h" 17 #include "clang/AST/DeclCXX.h" 18 #include "clang/AST/DeclarationName.h" 19 #include "clang/AST/ExprCXX.h" 20 #include "clang/AST/RecursiveASTVisitor.h" 21 #include "clang/AST/Type.h" 22 #include "clang/AST/TypeLoc.h" 23 #include "clang/Basic/LangOptions.h" 24 #include "clang/Basic/SourceLocation.h" 25 #include "clang/Basic/SourceManager.h" 26 #include "llvm/ADT/None.h" 27 #include "llvm/ADT/Optional.h" 28 #include "llvm/ADT/STLExtras.h" 29 #include "llvm/Support/Casting.h" 38 bool canHighlightName(DeclarationName
Name) {
39 if (Name.getNameKind() == DeclarationName::CXXConstructorName ||
40 Name.getNameKind() == DeclarationName::CXXUsingDirective)
42 auto *II = Name.getAsIdentifierInfo();
43 return II && !II->getName().empty();
46 llvm::Optional<HighlightingKind> kindForType(
const Type *TP);
47 llvm::Optional<HighlightingKind> kindForDecl(
const NamedDecl *D) {
48 if (
auto *USD = dyn_cast<UsingShadowDecl>(D)) {
49 if (
auto *Target = USD->getTargetDecl())
52 if (
auto *TD = dyn_cast<TemplateDecl>(D)) {
53 if (
auto *Templated = TD->getTemplatedDecl())
56 if (
auto *TD = dyn_cast<TypedefNameDecl>(D)) {
58 if (
auto K = kindForType(TD->getUnderlyingType().getTypePtrOrNull()))
66 if (
auto *RD = llvm::dyn_cast<RecordDecl>(D)) {
72 if (isa<ClassTemplateDecl>(D) || isa<RecordDecl>(D) ||
73 isa<CXXConstructorDecl>(D))
75 if (
auto *
MD = dyn_cast<CXXMethodDecl>(D))
78 if (isa<FieldDecl>(D))
82 if (isa<EnumConstantDecl>(D))
84 if (isa<ParmVarDecl>(D))
86 if (
auto *VD = dyn_cast<VarDecl>(D))
87 return VD->isStaticDataMember()
91 if (isa<BindingDecl>(D))
93 if (isa<FunctionDecl>(D))
95 if (isa<NamespaceDecl>(D) || isa<NamespaceAliasDecl>(D) ||
96 isa<UsingDirectiveDecl>(D))
98 if (isa<TemplateTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
99 isa<NonTypeTemplateParmDecl>(D))
103 llvm::Optional<HighlightingKind> kindForType(
const Type *TP) {
106 if (TP->isBuiltinType())
108 if (
auto *TD = dyn_cast<TemplateTypeParmType>(TP))
109 return kindForDecl(TD->getDecl());
110 if (
auto *TD = TP->getAsTagDecl())
111 return kindForDecl(TD);
115 llvm::Optional<HighlightingKind> kindForReference(
const ReferenceLoc &R) {
116 llvm::Optional<HighlightingKind> Result;
117 for (
const NamedDecl *
Decl : R.Targets) {
118 if (!canHighlightName(Decl->getDeclName()))
120 auto Kind = kindForDecl(Decl);
121 if (!
Kind || (Result &&
Kind != Result))
129 class HighlightingsBuilder {
131 HighlightingsBuilder(
const SourceManager &SourceMgr,
132 const LangOptions &LangOpts)
133 : SourceMgr(SourceMgr), LangOpts(LangOpts) {}
135 void addToken(HighlightingToken T) { Tokens.push_back(T); }
140 if (Loc.isMacroID()) {
142 if (!SourceMgr.isMacroArgExpansion(Loc))
144 Loc = SourceMgr.getSpellingLoc(Loc);
158 elog(
"Tried to add semantic token with an invalid range");
161 Tokens.push_back(HighlightingToken{
Kind, *
Range});
164 std::vector<HighlightingToken> collect(ParsedAST &
AST) && {
168 auto Last = std::unique(Tokens.begin(), Tokens.end());
169 Tokens.erase(Last, Tokens.end());
174 std::vector<HighlightingToken> NonConflicting;
175 NonConflicting.reserve(Tokens.size());
176 for (ArrayRef<HighlightingToken> TokRef = Tokens; !TokRef.empty();) {
177 ArrayRef<HighlightingToken> Conflicting =
178 TokRef.take_while([&](
const HighlightingToken &T) {
181 return T.R == TokRef.front().R;
185 if (Conflicting.size() == 1)
186 NonConflicting.push_back(TokRef.front());
189 TokRef = TokRef.drop_front(Conflicting.size());
192 for (
const Range &R :
AST.getMacros().SkippedRanges) {
195 assert(R.start.line <= R.end.line);
196 for (
int Line = R.start.line;
Line < R.end.line; ++
Line) {
202 {Position{
Line, 0}, Position{
Line, 0}}});
206 llvm::sort(NonConflicting);
207 return NonConflicting;
211 const SourceManager &SourceMgr;
212 const LangOptions &LangOpts;
213 std::vector<HighlightingToken> Tokens;
218 class CollectExtraHighlightings
219 :
public RecursiveASTVisitor<CollectExtraHighlightings> {
221 CollectExtraHighlightings(HighlightingsBuilder &H) : H(H) {}
223 bool VisitDecltypeTypeLoc(DecltypeTypeLoc L) {
224 if (
auto K = kindForType(L.getTypePtr()))
225 H.addToken(L.getBeginLoc(), *K);
229 bool VisitDeclaratorDecl(DeclaratorDecl *D) {
230 auto *AT = D->getType()->getContainedAutoType();
233 if (
auto K = kindForType(AT->getDeducedType().getTypePtrOrNull()))
234 H.addToken(D->getTypeSpecStartLoc(), *K);
238 bool VisitOverloadExpr(OverloadExpr *
E) {
239 if (!E->decls().empty())
245 bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
246 H.addToken(E->getMemberNameInfo().getLoc(),
251 bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) {
256 bool VisitDependentNameTypeLoc(DependentNameTypeLoc L) {
261 bool VisitDependentTemplateSpecializationTypeLoc(
262 DependentTemplateSpecializationTypeLoc L) {
272 bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Q) {
273 if (NestedNameSpecifier *NNS = Q.getNestedNameSpecifier()) {
277 return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(Q);
281 HighlightingsBuilder &H;
287 std::string encodeBase64(
const llvm::SmallVectorImpl<char> &Bytes) {
288 static const char Table[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" 289 "abcdefghijklmnopqrstuvwxyz" 293 for (I = 0; I + 2 < Bytes.size(); I += 3) {
294 uint32_t
X = (Bytes[I] << 16) + (Bytes[I + 1] << 8) + Bytes[I + 2];
295 Res += Table[(X >> 18) & 63];
296 Res += Table[(X >> 12) & 63];
297 Res += Table[(X >> 6) & 63];
298 Res += Table[X & 63];
300 if (I + 1 == Bytes.size()) {
301 uint32_t X = (Bytes[I] << 16);
302 Res += Table[(X >> 18) & 63];
303 Res += Table[(X >> 12) & 63];
305 }
else if (I + 2 == Bytes.size()) {
306 uint32_t X = (Bytes[I] << 16) + (Bytes[I + 1] << 8);
307 Res += Table[(X >> 18) & 63];
308 Res += Table[(X >> 12) & 63];
309 Res += Table[(X >> 6) & 63];
315 void write32be(uint32_t I, llvm::raw_ostream &OS) {
316 std::array<char, 4> Buf;
317 llvm::support::endian::write32be(Buf.data(), I);
318 OS.write(Buf.data(), Buf.size());
321 void write16be(uint16_t I, llvm::raw_ostream &OS) {
322 std::array<char, 2> Buf;
323 llvm::support::endian::write16be(Buf.data(), I);
324 OS.write(Buf.data(), Buf.size());
329 ArrayRef<HighlightingToken>
330 takeLine(ArrayRef<HighlightingToken> AllTokens,
331 ArrayRef<HighlightingToken>::iterator StartLineIt,
int Line) {
332 return ArrayRef<HighlightingToken>(StartLineIt, AllTokens.end())
333 .take_while([Line](
const HighlightingToken &Token) {
334 return Token.R.start.line ==
Line;
344 CollectExtraHighlightings(
Builder).TraverseAST(C);
347 if (
auto Kind = kindForReference(R))
352 for (
const auto &M : SIDToRefs.second)
356 Builder.addToken({HighlightingKind::Macro, M});
358 return std::move(
Builder).collect(AST);
364 return OS <<
"Variable";
366 return OS <<
"LocalVariable";
368 return OS <<
"Parameter";
370 return OS <<
"Function";
372 return OS <<
"Method";
374 return OS <<
"StaticMethod";
376 return OS <<
"Field";
378 return OS <<
"StaticField";
380 return OS <<
"Class";
384 return OS <<
"EnumConstant";
386 return OS <<
"Typedef";
388 return OS <<
"DependentType";
390 return OS <<
"DependentName";
392 return OS <<
"Namespace";
394 return OS <<
"TemplateParameter";
396 return OS <<
"Primitive";
398 return OS <<
"Macro";
400 return OS <<
"InactiveCode";
402 llvm_unreachable(
"invalid HighlightingKind");
405 std::vector<LineHighlightings>
407 ArrayRef<HighlightingToken> Old) {
408 assert(std::is_sorted(New.begin(), New.end()) &&
409 "New must be a sorted vector");
410 assert(std::is_sorted(Old.begin(), Old.end()) &&
411 "Old must be a sorted vector");
425 std::vector<LineHighlightings> DiffedLines;
427 ArrayRef<HighlightingToken> NewLine(New.begin(),
428 static_cast<size_t>(0));
429 ArrayRef<HighlightingToken> OldLine(Old.begin(),
430 static_cast<size_t>(0));
431 auto NewEnd = New.end();
432 auto OldEnd = Old.end();
433 auto NextLineNumber = [&]() {
434 int NextNew = NewLine.end() != NewEnd ? NewLine.end()->R.start.line
435 : std::numeric_limits<int>::max();
436 int NextOld = OldLine.end() != OldEnd ? OldLine.end()->R.start.line
437 : std::numeric_limits<int>::max();
438 return std::min(NextNew, NextOld);
441 for (
int LineNumber = 0; NewLine.end() < NewEnd || OldLine.end() < OldEnd;
442 LineNumber = NextLineNumber()) {
443 NewLine = takeLine(New, NewLine.end(), LineNumber);
444 OldLine = takeLine(Old, OldLine.end(), LineNumber);
445 if (NewLine != OldLine) {
446 DiffedLines.push_back({LineNumber, NewLine,
false});
449 auto &AddedLine = DiffedLines.back();
451 if (T.Kind == HighlightingKind::InactiveCode) {
452 AddedLine.IsInactive = true;
464 return std::tie(L.
R, L.
Kind) == std::tie(R.
R, R.
Kind);
467 return std::tie(L.
R, L.
Kind) < std::tie(R.
R, R.
Kind);
473 std::vector<SemanticHighlightingInformation>
475 if (Tokens.size() == 0)
480 std::vector<SemanticHighlightingInformation>
Lines;
481 Lines.reserve(Tokens.size());
482 for (
const auto &
Line : Tokens) {
483 llvm::SmallVector<char, 128> LineByteTokens;
484 llvm::raw_svector_ostream OS(LineByteTokens);
485 for (
const auto &Token :
Line.Tokens) {
491 write32be(Token.R.start.character, OS);
492 write16be(Token.R.end.character - Token.R.start.character, OS);
493 write16be(static_cast<int>(Token.Kind), OS);
496 Lines.push_back({
Line.Line, encodeBase64(LineByteTokens),
Line.IsInactive});
506 return "entity.name.function.cpp";
508 return "entity.name.function.method.cpp";
510 return "entity.name.function.method.static.cpp";
512 return "variable.other.cpp";
514 return "variable.other.local.cpp";
516 return "variable.parameter.cpp";
518 return "variable.other.field.cpp";
520 return "variable.other.field.static.cpp";
522 return "entity.name.type.class.cpp";
524 return "entity.name.type.enum.cpp";
526 return "variable.other.enummember.cpp";
528 return "entity.name.type.typedef.cpp";
530 return "entity.name.type.dependent.cpp";
532 return "entity.name.other.dependent.cpp";
534 return "entity.name.namespace.cpp";
536 return "entity.name.type.template.cpp";
538 return "storage.type.primitive.cpp";
540 return "entity.name.function.preprocessor.cpp";
542 return "meta.disabled";
544 llvm_unreachable(
"unhandled HighlightingKind");
SourceLocation Loc
'#' location in the include directive
const FunctionDecl * Decl
std::vector< HighlightingToken > Tokens
Information about a reference written in the source code, independent of the actual AST node that thi...
bool operator==(const HoverInfo::Param &LHS, const HoverInfo::Param &RHS)
bool isInsideMainFile(SourceLocation Loc, const SourceManager &SM)
Returns true iff Loc is inside the main file.
llvm::StringRef toTextMateScope(HighlightingKind Kind)
Converts a HighlightingKind to a corresponding TextMate scope (https://manual.macromates.com/en/language_grammars).
Documents should not be synced at all.
void elog(const char *Fmt, Ts &&... Vals)
ASTContext & getASTContext()
Note that the returned ast will not contain decls from the preamble that were not deserialized during...
std::vector< Range > UnknownMacros
llvm::DenseMap< SymbolID, std::vector< Range > > MacroRefs
std::vector< SemanticHighlightingInformation > toSemanticHighlightingInformation(llvm::ArrayRef< LineHighlightings > Tokens)
Convert to LSP's semantic highlighting information.
SourceLocation NameLoc
Start location of the last name part, i.e. 'foo' in 'ns::foo<int>'.
bool operator<(const Ref &L, const Ref &R)
static constexpr llvm::StringLiteral Name
std::vector< LineHighlightings > diffHighlightings(ArrayRef< HighlightingToken > New, ArrayRef< HighlightingToken > Old)
Return a line-by-line diff between two highlightings.
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
Stores and provides access to parsed AST.
CodeCompletionBuilder Builder
SourceManager & getSourceManager()
const MainFileMacros & getMacros() const
Gets all macro references (definition, expansions) present in the main file, including those in the p...
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static URISchemeRegistry::Add< TestScheme > X(TestScheme::Scheme, "Test schema")
Contains all information about highlightings on a single line.
void findExplicitReferences(const Stmt *S, llvm::function_ref< void(ReferenceLoc)> Out)
Recursively traverse S and report all references explicitly written in the code.
static GeneratorRegistry::Add< MDGenerator > MD(MDGenerator::Format, "Generator for MD output.")
CharSourceRange Range
SourceRange for the file name.
std::vector< HighlightingToken > getSemanticHighlightings(ParsedAST &AST)
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)