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 <clang/Basic/SourceLocation.h>
25#include <string>
26#include <map>
27#include <unordered_map>
28#include <set>
29#include <vector>
30#include <clang/AST/Mangle.h>
31#include "commenthandler.h"
32#include "generator.h"
33
34struct ProjectManager;
35struct ProjectInfo;
36class PreprocessorCallback;
37
38namespace clang {
39class Preprocessor;
40class NamedDecl;
41class MangleContext;
42class Type;
43class QualType;
44class Decl;
45class FileEntry;
46}
47
48/* Wrapper for the change in the name in clang 3.5 */
49template <typename T> auto getResultType(T *decl) -> decltype(decl->getResultType())
50{ return decl->getResultType(); }
51template <typename T> auto getResultType(T *decl) -> decltype(decl->getReturnType())
52{ return decl->getReturnType(); }
53
54typedef std::pair<unsigned, unsigned> pathTo_cache_key_t;
55namespace std {
56 template <>
57 struct hash<pathTo_cache_key_t>
58 {
59 size_t operator()(const pathTo_cache_key_t& k) const noexcept {
60 return k.first ^ k.second;
61 }
62 };
63}
64
65class Annotator {
66public:
67 enum DeclType { Declaration, Definition, Use, Use_Read, Use_Write, Use_Address, Use_Call, Use_MemberAccess, Use_NestedName, Override, Inherit };
68 enum TokenType { Ref, Member, Type, Decl, Call, Namespace, Typedef, Enum, EnumDecl, Label };
69private:
70 enum class Visibility {
71 Local, // Local to a Function
72 Static, // If it is only visible to this file
73 Global // Globaly visible.
74 };
75
76 Visibility getVisibility(const clang::NamedDecl *);
77
78 std::map<clang::FileID, std::pair<bool, std::string> > cache;
79 std::map<clang::FileID, ProjectInfo* > project_cache;
80 std::map<clang::FileID, Generator> generators;
81
82 std::string htmlNameForFile(clang::FileID id); // keep a cache;
83
84 void addReference(const std::string& ref, clang::SourceRange refLoc, Annotator::TokenType type,
85 Annotator::DeclType dt, const std::string &typeRef, clang::Decl *decl);
86
87 struct Reference {
88 DeclType what;
89 clang::SourceRange loc;
90 std::string typeOrContext;
91 };
92 std::map<std::string, std::vector<Reference>> references;
93 std::map<std::string, ssize_t> structure_sizes;
94 std::map<std::string, ssize_t> field_offsets;
95 struct SubRef {
96 std::string ref;
97 std::string type;
98 enum Type { None, Function, Member, Static } what = None;
99 };
100 std::map<std::string, std::vector<SubRef>> sub_refs;
101 std::unordered_map<pathTo_cache_key_t, std::string> pathTo_cache;
102 CommentHandler commentHandler;
103
104 std::unique_ptr<clang::MangleContext> mangle;
105 std::unordered_map<void *, std::pair<std::string, std::string> > mangle_cache; // canonical Decl* -> ref, escapred_title
106 std::pair<std::string, std::string> getReferenceAndTitle(clang::NamedDecl* decl);
107 // project -> { pretty name, ref }
108 std::map<std::string, std::string> functionIndex;
109
110 std::unordered_map<unsigned, int> localeNumbers;
111
112 std::map<clang::FileID, std::set<std::string> > interestingDefinitionsInFile;
113
114 std::string args;
115 clang::SourceManager *sourceManager = nullptr;
116 const clang::LangOptions *langOption = nullptr;
117
118 void syntaxHighlight(Generator& generator, clang::FileID FID, clang::Sema&);
119public:
120 explicit Annotator(ProjectManager &pm) : projectManager(pm) {}
121 ~Annotator();
122
123 ProjectManager &projectManager;
124
125 void setSourceMgr(clang::SourceManager &sm, const clang::LangOptions &lo)
126 { sourceManager = &sm; langOption = &lo; }
127 void setMangleContext(clang::MangleContext *m) { mangle.reset(m); }
128 clang::SourceManager &getSourceMgr() { return *sourceManager; }
129 const clang::LangOptions &getLangOpts() const { return *langOption; }
130 void setArgs(std::string a) { args = std::move(a); }
131
132 bool generate(clang::Sema&, bool WasInDatabase);
133
134 /**
135 * Returns a string with the URL to go from one file to an other.
136 * In case the file is in an external project that needs a data-proj tag, the proj
137 * string is set to the project name.
138 **/
139 std::string pathTo(clang::FileID From, clang::FileID To, std::string *proj = nullptr);
140 std::string pathTo(clang::FileID From, const clang::FileEntry* To);
141
142 /**
143 * Registers that the code in the given \a range refers to the specified declaration.
144 * This will highlight the rights portion of the code and registers it in the database.
145 *
146 * When the range.getEndLocation refers to an invalid location, this means this is a
147 * virtual range with no associated token (e.g. implicit conversions) which will be handled
148 * with an empty <span>.
149 *
150 * Only use typeRef for declarations (or definition), only use usedContext for uses
151 */
152 void registerReference(clang::NamedDecl *decl, clang::SourceRange range,
153 TokenType type, DeclType declType = Annotator::Use,
154 std::string typeRef = std::string(),
155 clang::NamedDecl *usedContext = nullptr);
156 void registerUse(clang::NamedDecl* decl, clang::SourceRange range, TokenType tt,
157 clang::NamedDecl* currentContext, DeclType useType = Use) {
158 return registerReference(decl, range, tt, useType, {}, currentContext);
159 }
160 void registerOverride(clang::NamedDecl* decl, clang::NamedDecl* overrided, clang::SourceLocation loc);
161 // same, but for macro
162 void registerMacro(const std::string &ref, clang::SourceLocation refLoc, DeclType declType);
163
164 // Class names, structs, objective C identifiers, main function
165 void registerInterestingDefinition(clang::SourceRange range, clang::NamedDecl *decl);
166
167 /**
168 * Wrap the source range in an HTML tag
169 */
170 void annotateSourceRange(clang::SourceRange range, std::string tag, std::string attributes);
171
172 void reportDiagnostic(clang::SourceRange range, const std::string& msg, const std::string& clas);
173
174 bool shouldProcess(clang::FileID);
175 Generator &generator(clang::FileID fid) { return generators[fid]; }
176
177 std::string getTypeRef(clang::QualType type);
178 std::string computeClas(clang::NamedDecl* decl);
179 std::string getContextStr(clang::NamedDecl* usedContext);
180 /**
181 * returns the reference of a class iff this class is visible
182 * (that is, if a tooltip file should be generated for it)
183 */
184 std::string getVisibleRef(clang::NamedDecl* Decl);
185
186 std::string externalProjectForFile(clang::FileID fid);
187};
188