1/****************************************************************************
2 * Copyright (C) 2012-2016 Woboq GmbH
3 * Olivier Goffart <contact at woboq.com>
4 * https://woboq.com/codebrowser.html
5 *
6 * This file is part of the Woboq Code Browser.
7 *
8 * Commercial License Usage:
9 * Licensees holding valid commercial licenses provided by Woboq may use
10 * this file in accordance with the terms contained in a written agreement
11 * between the licensee and Woboq.
12 * For further information see https://woboq.com/codebrowser.html
13 *
14 * Alternatively, this work may be used under a Creative Commons
15 * Attribution-NonCommercial-ShareAlike 3.0 (CC-BY-NC-SA 3.0) License.
16 * http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US
17 * This license does not allow you to use the code browser to assist the
18 * development of your commercial software. If you intent to do so, consider
19 * purchasing a commercial licence.
20 ****************************************************************************/
21
22#pragma once
23
24#include "annotator.h"
25#include "qtsupport.h"
26#include <clang/AST/ASTConsumer.h>
27#include <clang/AST/Attr.h>
28#include <clang/AST/DeclGroup.h>
29#include <clang/AST/Decl.h>
30#include <clang/AST/Stmt.h>
31#include <clang/AST/RecursiveASTVisitor.h>
32#include <clang/AST/Mangle.h>
33#include <clang/Lex/Lexer.h>
34#include <clang/Lex/Preprocessor.h>
35#include <clang/Basic/Version.h>
36#include <llvm/Support/SaveAndRestore.h>
37
38#include <iostream>
39#include <deque>
40
41struct BrowserASTVisitor : clang::RecursiveASTVisitor<BrowserASTVisitor> {
42 typedef clang::RecursiveASTVisitor<BrowserASTVisitor> Base;
43 Annotator &annotator;
44 clang::NamedDecl *currentContext = nullptr;
45 int recursionCount = 0; // Used to avoid a stack overflow
46 bool isNestedNameSpecifier = false;
47
48 struct : std::deque<clang::Expr *> {
49 clang::Expr *topExpr = 0;
50 Annotator::DeclType topType = Annotator::Use;
51 } expr_stack;
52
53 BrowserASTVisitor(Annotator &R) : annotator(R) {}
54
55 bool VisitTypedefNameDecl(clang::TypedefNameDecl *d) {
56 annotator.registerReference(d, d->getLocation(), Annotator::Typedef, Annotator::Declaration,
57 annotator.getTypeRef(d->getUnderlyingType()));
58 return true;
59 }
60
61 bool VisitTagDecl(clang::TagDecl *d) {
62 if(!shouldProcess(d)) return false;
63 if (d->isThisDeclarationADefinition()) {
64 if (clang::CXXRecordDecl* cxx = llvm::dyn_cast<clang::CXXRecordDecl>(d)) {
65 for (auto it = cxx->bases_begin(); it != cxx->bases_end(); ++it) {
66 if (! it->getType()->getAsCXXRecordDecl()) {
67// std::cerr << " INHERITING but not from a CXXRecrod " << std::endl;
68// it->getType().dump();
69 // probably template type... FIXME
70 continue;
71 }
72 annotator.registerOverride(d, it->getType()->getAsCXXRecordDecl(), d->getLocation());
73 }
74 }
75 }
76 annotator.registerReference(d, d->getLocation(), Annotator::Type,
77 d->isThisDeclarationADefinition() ? Annotator::Definition : Annotator::Declaration);
78 return true;
79 }
80
81 bool VisitNamespaceDecl(clang::NamespaceDecl *d) {
82 annotator.registerReference(d, d->getLocation(), Annotator::Namespace, Annotator::Declaration);
83 return true;
84 }
85 bool VisitNamespaceAliasDecl(clang::NamespaceAliasDecl *d) {
86 annotator.registerReference(d, d->getLocation(), Annotator::Namespace, Annotator::Declaration);
87 annotator.registerReference(d, d->getTargetNameLoc() , Annotator::Namespace);
88 return true;
89 }
90 bool VisitFunctionDecl(clang::FunctionDecl *d) {
91 if(!shouldProcess(d)) return false;
92 std::string typeText;
93 {
94 llvm::raw_string_ostream typeTextStream(typeText);
95
96 bool isConst = false;
97 if (clang::CXXMethodDecl *cxx = llvm::dyn_cast<clang::CXXMethodDecl>(d)) {
98 if (cxx->isStatic())
99 typeTextStream << "static ";
100 isConst = cxx->isConst();
101 if (cxx->isThisDeclarationADefinition()) {
102 for (auto it = cxx->begin_overridden_methods(); it != cxx->end_overridden_methods(); ++it) {
103 const clang::CXXMethodDecl *ovr = (*it)->getCanonicalDecl();
104 annotator.registerOverride(d, const_cast<clang::CXXMethodDecl*>(ovr), d->getNameInfo().getBeginLoc());
105 }
106 }
107 }
108 typeTextStream << annotator.getTypeRef(getResultType(d)) << " " << d->getQualifiedNameAsString() << "(";
109 for (unsigned int i = 0; i < d->getNumParams(); i++) {
110 if (i!=0) typeTextStream << ", ";
111 clang::ParmVarDecl* PVD = d->getParamDecl(i);
112 typeTextStream << annotator.getTypeRef(PVD->getType()) << " " << PVD->getName();
113 if (PVD->hasDefaultArg() && !PVD->hasUninstantiatedDefaultArg()) {
114 typeTextStream << " = ";
115 PVD->getDefaultArg()->printPretty(typeTextStream, 0, annotator.getLangOpts());
116 }
117 }
118 typeTextStream << ")";
119 if (isConst) {
120 typeTextStream << " const";
121 }
122 }
123
124 bool isDefinition = d->isThisDeclarationADefinition() || d->hasAttr<clang::AliasAttr>();
125
126 annotator.registerReference(d, d->getNameInfo().getSourceRange(), Annotator::Decl,
127 isDefinition ? Annotator::Definition : Annotator::Declaration,
128 typeText);
129 return true;
130 }
131 bool VisitEnumConstantDecl(clang::EnumConstantDecl *d) {
132 annotator.registerReference(d, d->getLocation(), Annotator::EnumDecl, Annotator::Declaration, d->getInitVal().toString(10));
133 return true;
134 }
135 bool VisitVarDecl(clang::VarDecl *d) {
136 if(!shouldProcess(d)) return false;
137 annotator.registerReference(d, d->getLocation(), Annotator::Decl,
138 d->isThisDeclarationADefinition() ? Annotator::Definition : Annotator::Declaration,
139 annotator.getTypeRef(d->getType()));
140 return true;
141 }
142 bool VisitFieldDecl(clang::FieldDecl *d) {
143 annotator.registerReference(d, d->getLocation(), Annotator::Decl, Annotator::Declaration,
144 annotator.getTypeRef(d->getType()));
145 return true;
146 }
147
148 bool VisitMemberExpr(clang::MemberExpr *e) {
149 auto range = e->getMemberNameInfo().getSourceRange();
150 if (range.getBegin().isInvalid()) {
151 // implicit conversion operator;
152 range = {e->getSourceRange().getBegin(), clang::SourceLocation{}};
153 }
154 annotator.registerUse(e->getMemberDecl(), range,
155 isMember(e->getMemberDecl()) ? Annotator::Member : Annotator::Ref,
156 currentContext, classify());
157 return true;
158 }
159 bool VisitDeclRefExpr(clang::DeclRefExpr *e) {
160 clang::ValueDecl* decl = e->getDecl();
161 annotator.registerUse(decl, e->getNameInfo().getSourceRange(),
162 llvm::isa<clang::EnumConstantDecl>(decl) ? Annotator::EnumDecl :
163 isMember(decl) ? Annotator::Member : Annotator::Ref,
164 currentContext, classify());
165 return true;
166 }
167
168 bool VisitDesignatedInitExpr(clang::DesignatedInitExpr *e) {
169#if CLANG_VERSION_MAJOR==3 && CLANG_VERSION_MINOR<5
170 llvm::ArrayRef<clang::DesignatedInitExpr::Designator> designators{e->designators_begin(),
171 e->designators_end()};
172#else
173 auto designators = e->designators();
174#endif
175 for(auto it : designators) {
176 if (it.isFieldDesignator()) {
177 if (auto decl = it.getField()) {
178 annotator.registerUse(decl, it.getFieldLoc(), Annotator::Ref, currentContext,
179 Annotator::Use_Write);
180 }
181 }
182 }
183 return true;
184 }
185
186 bool VisitTypedefTypeLoc(clang::TypedefTypeLoc TL) {
187 clang::SourceRange range = TL.getSourceRange();
188 annotator.registerReference(TL.getTypedefNameDecl(), range, Annotator::Typedef, Annotator::Use,
189 annotator.getTypeRef(TL.getTypedefNameDecl()->getUnderlyingType()),
190 currentContext);
191 return true;
192 }
193
194 bool VisitTagTypeLoc(clang::TagTypeLoc TL) {
195 clang::SourceRange range = TL.getSourceRange();
196 annotator.registerUse(TL.getDecl(), range.getBegin(), Annotator::Type, currentContext,
197 isNestedNameSpecifier ? Annotator::Use_NestedName : Annotator::Use);
198 return true;
199 }
200
201 bool VisitTemplateSpecializationTypeLoc(clang::TemplateSpecializationTypeLoc TL) {
202
203 clang::TemplateDecl* decl = TL.getTypePtr()->getTemplateName().getAsTemplateDecl();
204 if (decl) {
205 auto loc = TL.getTemplateNameLoc();
206 annotator.registerUse(decl, loc, Annotator::Type, currentContext);
207 } else {
208 std::cerr << "VisitTemplateSpecializationTypeLoc " << " "<< TL.getType().getAsString();
209 }
210 return true;
211 }
212
213 bool TraverseNestedNameSpecifierLoc(clang::NestedNameSpecifierLoc NNS) {
214 if (!NNS)
215 return true;
216
217 switch (NNS.getNestedNameSpecifier()->getKind()) {
218 case clang::NestedNameSpecifier::Namespace:
219 if (NNS.getNestedNameSpecifier()->getAsNamespace()->isAnonymousNamespace())
220 break;
221 annotator.registerReference(NNS.getNestedNameSpecifier()->getAsNamespace(),
222 NNS.getSourceRange(), Annotator::Namespace);
223 return true; // skip prefixes
224 case clang::NestedNameSpecifier::NamespaceAlias:
225 annotator.registerReference(NNS.getNestedNameSpecifier()->getAsNamespaceAlias()->getAliasedNamespace(),
226 NNS.getSourceRange(), Annotator::Namespace);
227 return true; //skip prefixes
228 default: break;
229 }
230 llvm::SaveAndRestore<bool> nns(isNestedNameSpecifier, true);
231 return Base::TraverseNestedNameSpecifierLoc(NNS);
232 }
233 bool TraverseUsingDirectiveDecl(clang::UsingDirectiveDecl *d) {
234 auto qualBeginLoc = d->getQualifierLoc().getBeginLoc();
235 auto identLoc = d->getIdentLocation();
236 annotator.registerReference(d->getNominatedNamespace(),
237 { qualBeginLoc.isValid() ? qualBeginLoc : identLoc, identLoc },
238 Annotator::Namespace);
239 // don't call Base::TraverseUsingDirectiveDecl in order to skip prefix
240 return true;
241 }
242
243 // the initializers would not be highlighted otherwise
244 bool TraverseConstructorInitializer(clang::CXXCtorInitializer *Init) {
245 if (Init->isAnyMemberInitializer() && Init->isWritten()) {
246 annotator.registerUse(Init->getAnyMember(), Init->getMemberLocation(),
247 Init->isMemberInitializer() ? Annotator::Member : Annotator::Ref,
248 currentContext, Init->isMemberInitializer() ? Annotator::Use_Write : Annotator::Use);
249 }
250 decltype(expr_stack) old_stack;
251 std::swap(expr_stack, old_stack);
252 expr_stack.topExpr = Init->getInit();
253 expr_stack.topType = Annotator::Use_Read;
254 Base::TraverseConstructorInitializer(Init);
255 std::swap(expr_stack, old_stack);
256 return true;
257 }
258
259 // try to put a link to the right constructor
260 bool VisitCXXConstructExpr(clang::CXXConstructExpr *ctr) {
261 if (clang::CXXConstructorDecl *decl = ctr->getConstructor()) {
262 clang::SourceLocation parenLoc = ctr->getParenOrBraceRange().getBegin();
263 if (parenLoc.isValid()) {
264 // Highlight the opening parenthese
265 annotator.registerUse(decl, parenLoc, Annotator::Ref, currentContext, Annotator::Use_Call);
266 } else if (!ctr->isElidable()) {
267 annotator.registerUse(decl, {ctr->getLocation(), clang::SourceLocation{}} ,
268 Annotator::Ref, currentContext, Annotator::Use_Call);
269 }
270 }
271 QtSupport qt{annotator, currentContext};
272 qt.visitCXXConstructExpr(ctr);
273 return true;
274 }
275
276
277 bool VisitCallExpr(clang::CallExpr *e) {
278 // Find out arguments passed by references
279 auto decl = e->getDirectCallee();
280 if (decl && !llvm::isa<clang::CXXOperatorCallExpr>(e)) {
281 // Don't handle CXXOperatorCallExpr because it is obvious for operator= += and so on.
282 // And also because of the wierd rules regarding the member operators and their number
283 // of arguments
284 for (unsigned int i = 0; decl && i < e->getNumArgs() && i < decl->getNumParams() ; ++i) {
285 auto t = decl->getParamDecl(i)->getType();
286 if (t->isLValueReferenceType() && !t.getNonReferenceType().isConstQualified()) {
287 annotator.annotateSourceRange(e->getArg(i)->getSourceRange(), "span", "class='refarg'");
288 }
289 }
290 }
291
292 // support QObject::connect SIGNAL and SLOT
293 QtSupport qt{annotator, currentContext};
294 qt.visitCallExpr(e);
295 return true;
296 }
297
298
299 bool VisitGotoStmt(clang::GotoStmt *stm) {
300 if (auto label = stm->getLabel()) {
301 annotator.registerReference(label, stm->getLabelLoc(), Annotator::Label, Annotator::Use, {}, currentContext);
302 }
303 return true;
304 }
305 bool VisitLabelStmt(clang::LabelStmt *stm) {
306 if (auto label = stm->getDecl()) {
307 annotator.registerReference(label, stm->getIdentLoc(), Annotator::Label, Annotator::Declaration, {}, currentContext);
308 }
309 return true;
310 }
311
312 bool TraverseDecl(clang::Decl *d) {
313 if (!d) return true;
314 auto saved = currentContext;
315 if (clang::FunctionDecl::classof(d) || clang::RecordDecl::classof(d) ||
316 clang::NamespaceDecl::classof(d) || clang::TemplateDecl::classof(d)) {
317 currentContext = llvm::dyn_cast<clang::NamedDecl>(d);
318 }
319 if (auto v = llvm::dyn_cast<clang::VarDecl>(d)) {
320 if (v->getInit() && !expr_stack.topExpr) {
321 expr_stack.topExpr = v->getInit();
322 auto t = v->getType();
323 expr_stack.topType = (t->isReferenceType() && !t.getNonReferenceType().isConstQualified()) ?
324 Annotator::Use_Address : Annotator::Use_Read;
325 }
326 }
327 Base::TraverseDecl(d);
328 currentContext = saved;
329 return true;
330 }
331
332 // Since we cannot find up the parent of a node, we keep a stack of parents
333 bool TraverseStmt(clang::Stmt *s) {
334 if (++recursionCount > 10000) {
335 // Give up if the stack is too big to avoid stack overflow
336 std::cerr << "TraverseStmt: Stack overflow, giving up traversal";
337 return true;
338 }
339 auto e = llvm::dyn_cast_or_null<clang::Expr>(s);
340 decltype(expr_stack) old_stack;
341 if (e) {
342 expr_stack.push_front(e);
343 } else {
344 std::swap(old_stack, expr_stack);
345 if (auto i = llvm::dyn_cast_or_null<clang::IfStmt>(s)) {
346 expr_stack.topExpr = i->getCond();
347 expr_stack.topType = Annotator::Use_Read;
348 } else if (auto r = llvm::dyn_cast_or_null<clang::ReturnStmt>(s)) {
349 expr_stack.topExpr = r->getRetValue();
350 if (auto f = llvm::dyn_cast_or_null<clang::FunctionDecl>(currentContext)) {
351 auto t = getResultType(f);
352 if (t->isReferenceType() /*&& !t.getNonReferenceType().isConstQualified()*/)
353 expr_stack.topType = Annotator::Use_Address; // non const reference
354 else
355 expr_stack.topType = Annotator::Use_Read; // anything else is considered as read;
356 }
357 } else if (auto sw = llvm::dyn_cast_or_null<clang::SwitchStmt>(s)) {
358 expr_stack.topExpr = sw->getCond();
359 expr_stack.topType = Annotator::Use_Read;
360 } else if (auto d = llvm::dyn_cast_or_null<clang::DoStmt>(s)) {
361 expr_stack.topExpr = d->getCond();
362 expr_stack.topType = Annotator::Use_Read;
363 } else if (auto w = llvm::dyn_cast_or_null<clang::WhileStmt>(s)) {
364 expr_stack.topExpr = w->getCond();
365 expr_stack.topType = Annotator::Use_Read;
366 }
367 }
368 auto r = Base::TraverseStmt(s);
369 if (e) {
370 expr_stack.pop_front();
371 } else {
372 std::swap(old_stack, expr_stack);
373 }
374 recursionCount--;
375 return r;
376 }
377
378#if CLANG_VERSION_MAJOR == 3 && CLANG_VERSION_MINOR < 8
379 bool shouldUseDataRecursionFor(clang::Stmt *S) {
380 // We need to disable this data recursion feature otherwise this break the detection
381 // of parents (expr_stack). Especially for the CaseStmt
382 return false;
383 }
384#endif
385
386 bool TraverseDeclarationNameInfo(clang::DeclarationNameInfo NameInfo) {
387 // Do not visit the TypeLoc of constructor or destructors
388 return true;
389 }
390
391private:
392
393 Annotator::DeclType classify() {
394 bool first = true;
395 clang::Expr *previous = nullptr;
396 for (auto expr : expr_stack) {
397 if (first) {
398 previous = expr;
399 first = false;
400 continue; //skip the first element (ourself)
401 }
402 if (llvm::isa<clang::MemberExpr>(expr)) {
403 return Annotator::Use_MemberAccess;
404 }
405 if (auto op = llvm::dyn_cast<clang::ImplicitCastExpr>(expr)) {
406 if (op->getCastKind() == clang::CK_LValueToRValue)
407 return Annotator::Use_Read;
408 }
409 if (auto op = llvm::dyn_cast<clang::BinaryOperator>(expr)) {
410 if (op->isAssignmentOp() && op->getLHS() == previous)
411 return Annotator::Use_Write;
412 return Annotator::Use_Read;
413 }
414 if (auto op = llvm::dyn_cast<clang::UnaryOperator>(expr)) {
415 if (op->isIncrementDecrementOp())
416 return Annotator::Use_Write;
417 if (op->isArithmeticOp() || op->getOpcode() == clang::UO_Deref)
418 return Annotator::Use_Read;
419 if (op->getOpcode() == clang::UO_AddrOf)
420 return Annotator::Use_Address;
421 return Annotator::Use;
422 }
423 if (auto op = llvm::dyn_cast<clang::CXXOperatorCallExpr>(expr)) {
424 // Special case for some of the CXXOperatorCallExpr to check if it is Use_Write
425 // Anything else goes through normal CallExpr
426 auto o = op->getOperator();
427 if (o == clang::OO_Equal || (o >= clang::OO_PlusEqual && o <= clang::OO_PipeEqual)
428 || (o >= clang::OO_LessLessEqual && o <= clang::OO_GreaterGreaterEqual)
429 || (o >= clang::OO_PlusPlus && o <= clang::OO_MinusMinus) ) {
430 if (op->getNumArgs() >= 1 && op->getArg(0) == previous) {
431 return Annotator::Use_Write;
432 }
433 }
434 }
435 if (auto call = llvm::dyn_cast<clang::CallExpr>(expr)) {
436 if (previous == call->getCallee())
437 return Annotator::Use_Call;
438 auto decl = call->getDirectCallee();
439 if (!decl) return Annotator::Use;
440 for (unsigned int i = 0; i < call->getNumArgs(); ++i) {
441 if (call->getArg(i) != previous)
442 continue;
443 if (llvm::isa<clang::CXXOperatorCallExpr>(call)
444 && decl->getNumParams() < call->getNumArgs()) {
445 // For example, member operators: first argument is the 'this'
446 if (i == 0)
447 return Annotator::Use_MemberAccess;
448 i--;
449 }
450 if (i >= decl->getNumParams())
451 break;
452 auto t = decl->getParamDecl(i)->getType();
453 if (t->isReferenceType() && !t.getNonReferenceType().isConstQualified())
454 return Annotator::Use_Address; // non const reference
455 return Annotator::Use_Read; // anything else is considered as read;
456 }
457 return Annotator::Use;
458 }
459 if (auto call = llvm::dyn_cast<clang::CXXConstructExpr>(expr)) {
460 auto decl = call->getConstructor();
461 for (unsigned int i = 0; i < call->getNumArgs(); ++i) {
462 if (!decl || decl->getNumParams() <= i)
463 break;
464 if (call->getArg(i) != previous)
465 continue;
466 auto t = decl->getParamDecl(i)->getType();
467 if (t->isReferenceType() && !t.getNonReferenceType().isConstQualified())
468 return Annotator::Use_Address; // non const reference
469 return Annotator::Use_Read; // anything else is considered as read;
470 }
471 return Annotator::Use;
472 }
473 previous = expr;
474 }
475 if (previous == expr_stack.topExpr)
476 return expr_stack.topType;
477 return Annotator::Use;
478 }
479
480
481 bool isMember(clang::NamedDecl *d) {
482 if (!currentContext)
483 return false;
484 clang::CXXRecordDecl *ctx = llvm::dyn_cast<clang::CXXRecordDecl>(currentContext->getDeclContext());
485 if (!ctx) return false;
486 if (d->getDeclContext() == ctx)
487 return true;
488
489 // try to see if it is in a inhertited class
490 clang::CXXRecordDecl *rec = llvm::dyn_cast<clang::CXXRecordDecl>(d->getDeclContext());
491 return rec && ctx->isDerivedFrom(rec);
492 }
493
494 bool shouldProcess(clang::NamedDecl *d) {
495 return annotator.shouldProcess(clang::FullSourceLoc(d->getLocation(),
496 annotator.getSourceMgr()).getExpansionLoc().getFileID());
497 }
498};
499