blob: eacf11a850974c2cb478c99c8f10d0e010933c28 [file] [log] [blame]
Julie Hockettd0f9a872018-06-04 17:22:20 +00001///===-- Representation.cpp - ClangDoc Representation -----------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines the merging of different types of infos. The data in the
11// calling Info is preserved during a merge unless that field is empty or
12// default. In that case, the data from the parameter Info is used to replace
13// the empty or default data.
14//
15// For most fields, the first decl seen provides the data. Exceptions to this
16// include the location and description fields, which are collections of data on
17// all decls related to a given definition. All other fields are ignored in new
18// decls unless the first seen decl didn't, for whatever reason, incorporate
19// data on that field (e.g. a forward declared class wouldn't have information
20// on members on the forward declaration, but would have the class name).
21//
22//===----------------------------------------------------------------------===//
23#include "Representation.h"
24#include "llvm/Support/Error.h"
25
26namespace clang {
27namespace doc {
28
Julie Hockett8899c292018-08-02 20:10:17 +000029namespace {
30
31const SymbolID EmptySID = SymbolID();
Julie Hockettd0f9a872018-06-04 17:22:20 +000032
33template <typename T>
Julie Hockett8899c292018-08-02 20:10:17 +000034llvm::Expected<std::unique_ptr<Info>>
35reduce(std::vector<std::unique_ptr<Info>> &Values) {
36 if (Values.empty())
37 return llvm::make_error<llvm::StringError>(" No values to reduce.\n",
38 llvm::inconvertibleErrorCode());
39 std::unique_ptr<Info> Merged = llvm::make_unique<T>(Values[0]->USR);
Julie Hockettd0f9a872018-06-04 17:22:20 +000040 T *Tmp = static_cast<T *>(Merged.get());
41 for (auto &I : Values)
42 Tmp->merge(std::move(*static_cast<T *>(I.get())));
Julie Hockett8899c292018-08-02 20:10:17 +000043 return std::move(Merged);
Julie Hockettd0f9a872018-06-04 17:22:20 +000044}
45
Julie Hockett8899c292018-08-02 20:10:17 +000046// Return the index of the matching child in the vector, or -1 if merge is not
47// necessary.
48template <typename T>
49int getChildIndexIfExists(std::vector<T> &Children, T &ChildToMerge) {
50 for (unsigned long I = 0; I < Children.size(); I++) {
51 if (ChildToMerge.USR == Children[I].USR)
52 return I;
53 }
54 return -1;
55}
56
57// For References, we don't need to actually merge them, we just don't want
58// duplicates.
59void reduceChildren(std::vector<Reference> &Children,
60 std::vector<Reference> &&ChildrenToMerge) {
61 for (auto &ChildToMerge : ChildrenToMerge) {
62 if (getChildIndexIfExists(Children, ChildToMerge) == -1)
63 Children.push_back(std::move(ChildToMerge));
64 }
65}
66
67void reduceChildren(std::vector<FunctionInfo> &Children,
68 std::vector<FunctionInfo> &&ChildrenToMerge) {
69 for (auto &ChildToMerge : ChildrenToMerge) {
70 int mergeIdx = getChildIndexIfExists(Children, ChildToMerge);
71 if (mergeIdx == -1) {
72 Children.push_back(std::move(ChildToMerge));
73 continue;
74 }
75 Children[mergeIdx].merge(std::move(ChildToMerge));
76 }
77}
78
79void reduceChildren(std::vector<EnumInfo> &Children,
80 std::vector<EnumInfo> &&ChildrenToMerge) {
81 for (auto &ChildToMerge : ChildrenToMerge) {
82 int mergeIdx = getChildIndexIfExists(Children, ChildToMerge);
83 if (mergeIdx == -1) {
84 Children.push_back(std::move(ChildToMerge));
85 continue;
86 }
87 Children[mergeIdx].merge(std::move(ChildToMerge));
88 }
89}
90
91} // namespace
92
Julie Hockettd0f9a872018-06-04 17:22:20 +000093// Dispatch function.
94llvm::Expected<std::unique_ptr<Info>>
95mergeInfos(std::vector<std::unique_ptr<Info>> &Values) {
96 if (Values.empty())
97 return llvm::make_error<llvm::StringError>("No info values to merge.\n",
Julie Hocketteb50a2e2018-07-20 18:49:55 +000098 llvm::inconvertibleErrorCode());
Julie Hockettd0f9a872018-06-04 17:22:20 +000099
100 switch (Values[0]->IT) {
101 case InfoType::IT_namespace:
102 return reduce<NamespaceInfo>(Values);
103 case InfoType::IT_record:
104 return reduce<RecordInfo>(Values);
105 case InfoType::IT_enum:
106 return reduce<EnumInfo>(Values);
107 case InfoType::IT_function:
108 return reduce<FunctionInfo>(Values);
109 default:
110 return llvm::make_error<llvm::StringError>("Unexpected info type.\n",
111 llvm::inconvertibleErrorCode());
112 }
113}
114
115void Info::mergeBase(Info &&Other) {
116 assert(mergeable(Other));
117 if (USR == EmptySID)
118 USR = Other.USR;
119 if (Name == "")
120 Name = Other.Name;
121 if (Namespace.empty())
122 Namespace = std::move(Other.Namespace);
123 // Unconditionally extend the description, since each decl may have a comment.
124 std::move(Other.Description.begin(), Other.Description.end(),
125 std::back_inserter(Description));
126}
127
128bool Info::mergeable(const Info &Other) {
Julie Hockett8899c292018-08-02 20:10:17 +0000129 return IT == Other.IT && USR == Other.USR;
Julie Hockettd0f9a872018-06-04 17:22:20 +0000130}
131
132void SymbolInfo::merge(SymbolInfo &&Other) {
133 assert(mergeable(Other));
134 if (!DefLoc)
135 DefLoc = std::move(Other.DefLoc);
136 // Unconditionally extend the list of locations, since we want all of them.
137 std::move(Other.Loc.begin(), Other.Loc.end(), std::back_inserter(Loc));
138 mergeBase(std::move(Other));
139}
140
141void NamespaceInfo::merge(NamespaceInfo &&Other) {
142 assert(mergeable(Other));
Julie Hockett8899c292018-08-02 20:10:17 +0000143 // Reduce children if necessary.
144 reduceChildren(ChildNamespaces, std::move(Other.ChildNamespaces));
145 reduceChildren(ChildRecords, std::move(Other.ChildRecords));
146 reduceChildren(ChildFunctions, std::move(Other.ChildFunctions));
147 reduceChildren(ChildEnums, std::move(Other.ChildEnums));
Julie Hockettd0f9a872018-06-04 17:22:20 +0000148 mergeBase(std::move(Other));
149}
150
151void RecordInfo::merge(RecordInfo &&Other) {
152 assert(mergeable(Other));
153 if (!TagType)
154 TagType = Other.TagType;
155 if (Members.empty())
156 Members = std::move(Other.Members);
157 if (Parents.empty())
158 Parents = std::move(Other.Parents);
159 if (VirtualParents.empty())
160 VirtualParents = std::move(Other.VirtualParents);
Julie Hockett8899c292018-08-02 20:10:17 +0000161 // Reduce children if necessary.
162 reduceChildren(ChildRecords, std::move(Other.ChildRecords));
163 reduceChildren(ChildFunctions, std::move(Other.ChildFunctions));
164 reduceChildren(ChildEnums, std::move(Other.ChildEnums));
Julie Hockettd0f9a872018-06-04 17:22:20 +0000165 SymbolInfo::merge(std::move(Other));
166}
167
168void EnumInfo::merge(EnumInfo &&Other) {
169 assert(mergeable(Other));
170 if (!Scoped)
171 Scoped = Other.Scoped;
172 if (Members.empty())
173 Members = std::move(Other.Members);
174 SymbolInfo::merge(std::move(Other));
175}
176
177void FunctionInfo::merge(FunctionInfo &&Other) {
178 assert(mergeable(Other));
179 if (!IsMethod)
180 IsMethod = Other.IsMethod;
181 if (!Access)
182 Access = Other.Access;
183 if (ReturnType.Type.USR == EmptySID && ReturnType.Type.Name == "")
184 ReturnType = std::move(Other.ReturnType);
185 if (Parent.USR == EmptySID && Parent.Name == "")
186 Parent = std::move(Other.Parent);
187 if (Params.empty())
188 Params = std::move(Other.Params);
189 SymbolInfo::merge(std::move(Other));
190}
191
192} // namespace doc
193} // namespace clang