1/*
2 * Copyright 2010, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "slang_rs_export_element.h"
18
19#include "clang/AST/Decl.h"
20#include "clang/AST/Type.h"
21
22#include "clang/Basic/SourceLocation.h"
23#include "clang/Basic/IdentifierTable.h"
24
25#include "slang_assert.h"
26#include "slang_rs_context.h"
27#include "slang_rs_export_type.h"
28
29namespace slang {
30
31bool RSExportElement::Initialized = false;
32RSExportElement::ElementInfoMapTy RSExportElement::ElementInfoMap;
33
34void RSExportElement::Init() {
35  if (!Initialized) {
36    // Initialize ElementInfoMap
37#define ENUM_RS_DATA_ELEMENT(_name, _dt, _norm, _vsize)  \
38    {                                                         \
39      ElementInfo *EI = new ElementInfo;                      \
40      EI->type = RSExportPrimitiveType::DataType ## _dt;      \
41      EI->normalized = _norm;                                 \
42      EI->vsize = _vsize;                                     \
43                                                              \
44      llvm::StringRef Name(_name);                            \
45      ElementInfoMap.insert(                                  \
46          ElementInfoMapTy::value_type::Create(               \
47              Name.begin(),                                   \
48              Name.end(),                                     \
49              ElementInfoMap.getAllocator(),                  \
50              EI));                                           \
51    }
52#include "RSDataElementEnums.inc"
53
54    Initialized = true;
55  }
56  return;
57}
58
59RSExportType *RSExportElement::Create(RSContext *Context,
60                                      const clang::Type *T,
61                                      const ElementInfo *EI) {
62  // Create RSExportType corresponded to the @T first and then verify
63
64  llvm::StringRef TypeName;
65  RSExportType *ET = NULL;
66
67  if (!Initialized)
68    Init();
69
70  slangAssert(EI != NULL && "Element info not found");
71
72  if (!RSExportType::NormalizeType(T, TypeName, Context->getDiagnostics(),
73                                   NULL))
74    return NULL;
75
76  switch (T->getTypeClass()) {
77    case clang::Type::Builtin:
78    case clang::Type::Pointer: {
79      slangAssert(EI->vsize == 1 && "Element not a primitive class (please "
80                                    "check your macro)");
81      RSExportPrimitiveType *EPT =
82          RSExportPrimitiveType::Create(Context,
83                                        T,
84                                        TypeName,
85                                        EI->normalized);
86      // Verify
87      slangAssert(EI->type == EPT->getType() && "Element has unexpected type");
88      ET = EPT;
89      break;
90    }
91    case clang::Type::ExtVector: {
92      slangAssert(EI->vsize > 1 && "Element not a vector class (please check "
93                                   "your macro)");
94      RSExportVectorType *EVT =
95          RSExportVectorType::Create(Context,
96                                     static_cast<const clang::ExtVectorType*>(
97                                         T->getCanonicalTypeInternal()
98                                             .getTypePtr()),
99                                     TypeName,
100                                     EI->normalized);
101      // Verify
102      slangAssert(EI->type == EVT->getType() && "Element has unexpected type");
103      slangAssert(EI->vsize == EVT->getNumElement() && "Element has unexpected "
104                                                       "size of vector");
105      ET = EVT;
106      break;
107    }
108    default: {
109      // TODO(zonr): warn that type is not exportable
110      fprintf(stderr, "RSExportElement::Create : type '%s' is not exportable\n",
111              T->getTypeClassName());
112      break;
113    }
114  }
115
116  return ET;
117}
118
119RSExportType *RSExportElement::CreateFromDecl(RSContext *Context,
120                                              const clang::DeclaratorDecl *DD) {
121  const clang::Type* T = RSExportType::GetTypeOfDecl(DD);
122  const clang::Type* CT = GET_CANONICAL_TYPE(T);
123  const ElementInfo* EI = NULL;
124
125  // Note: RS element like rs_pixel_rgb elements are either in the type of
126  // primitive or vector.
127  if ((CT->getTypeClass() != clang::Type::Builtin) &&
128      (CT->getTypeClass() != clang::Type::ExtVector)) {
129    return RSExportType::Create(Context, T);
130  }
131
132  // Following the typedef chain to see whether it's an element name like
133  // rs_pixel_rgb or its alias (via typedef).
134  while (T != CT) {
135    if (T->getTypeClass() != clang::Type::Typedef) {
136      break;
137    } else {
138      const clang::TypedefType *TT = static_cast<const clang::TypedefType*>(T);
139      const clang::TypedefNameDecl *TD = TT->getDecl();
140      EI = GetElementInfo(TD->getName());
141      if (EI != NULL)
142        break;
143
144      T = TD->getUnderlyingType().getTypePtr();
145    }
146  }
147
148  if (EI == NULL) {
149    return RSExportType::Create(Context, T);
150  } else {
151    return RSExportElement::Create(Context, T, EI);
152  }
153}
154
155const RSExportElement::ElementInfo *
156RSExportElement::GetElementInfo(const llvm::StringRef &Name) {
157  if (!Initialized)
158    Init();
159
160  ElementInfoMapTy::const_iterator I = ElementInfoMap.find(Name);
161  if (I == ElementInfoMap.end())
162    return NULL;
163  else
164    return I->getValue();
165}
166
167}  // namespace slang
168