slang_rs_export_element.cpp revision 83f0c6261efc8f397fc2509e3862bc6d0eb1e1c4
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, _dk, _dt, _norm, _vsize)  \
38    {                                                         \
39      ElementInfo *EI = new ElementInfo;                      \
40      EI->kind = RSExportPrimitiveType::DataKind ## _dk;      \
41      EI->type = RSExportPrimitiveType::DataType ## _dt;      \
42      EI->normalized = _norm;                                 \
43      EI->vsize = _vsize;                                     \
44                                                              \
45      llvm::StringRef Name(_name);                            \
46      ElementInfoMap.insert(                                  \
47          ElementInfoMapTy::value_type::Create(               \
48              Name.begin(),                                   \
49              Name.end(),                                     \
50              ElementInfoMap.getAllocator(),                  \
51              EI));                                           \
52    }
53#include "RSDataElementEnums.inc"
54
55    Initialized = true;
56  }
57  return;
58}
59
60RSExportType *RSExportElement::Create(RSContext *Context,
61                                      const clang::Type *T,
62                                      const ElementInfo *EI) {
63  // Create RSExportType corresponded to the @T first and then verify
64
65  llvm::StringRef TypeName;
66  RSExportType *ET = NULL;
67
68  if (!Initialized)
69    Init();
70
71  slangAssert(EI != NULL && "Element info not found");
72
73  if (!RSExportType::NormalizeType(T, TypeName, Context->getDiagnostics(),
74                                   NULL))
75    return NULL;
76
77  switch (T->getTypeClass()) {
78    case clang::Type::Builtin:
79    case clang::Type::Pointer: {
80      slangAssert(EI->vsize == 1 && "Element not a primitive class (please "
81                                    "check your macro)");
82      RSExportPrimitiveType *EPT =
83          RSExportPrimitiveType::Create(Context,
84                                        T,
85                                        TypeName,
86                                        EI->kind,
87                                        EI->normalized);
88      // Verify
89      slangAssert(EI->type == EPT->getType() && "Element has unexpected type");
90      ET = EPT;
91      break;
92    }
93    case clang::Type::ExtVector: {
94      slangAssert(EI->vsize > 1 && "Element not a vector class (please check "
95                                   "your macro)");
96      RSExportVectorType *EVT =
97          RSExportVectorType::Create(Context,
98                                     static_cast<const clang::ExtVectorType*>(
99                                         T->getCanonicalTypeInternal()
100                                             .getTypePtr()),
101                                     TypeName,
102                                     EI->kind,
103                                     EI->normalized);
104      // Verify
105      slangAssert(EI->type == EVT->getType() && "Element has unexpected type");
106      slangAssert(EI->vsize == EVT->getNumElement() && "Element has unexpected "
107                                                       "size of vector");
108      ET = EVT;
109      break;
110    }
111    default: {
112      // TODO(zonr): warn that type is not exportable
113      fprintf(stderr, "RSExportElement::Create : type '%s' is not exportable\n",
114              T->getTypeClassName());
115      break;
116    }
117  }
118
119  return ET;
120}
121
122RSExportType *RSExportElement::CreateFromDecl(RSContext *Context,
123                                              const clang::DeclaratorDecl *DD) {
124  const clang::Type* T = RSExportType::GetTypeOfDecl(DD);
125  const clang::Type* CT = GET_CANONICAL_TYPE(T);
126  const ElementInfo* EI = NULL;
127
128  // Note: RS element like rs_pixel_rgb elements are either in the type of
129  // primitive or vector.
130  if ((CT->getTypeClass() != clang::Type::Builtin) &&
131      (CT->getTypeClass() != clang::Type::ExtVector)) {
132    return RSExportType::Create(Context, T);
133  }
134
135  // Following the typedef chain to see whether it's an element name like
136  // rs_pixel_rgb or its alias (via typedef).
137  while (T != CT) {
138    if (T->getTypeClass() != clang::Type::Typedef) {
139      break;
140    } else {
141      const clang::TypedefType *TT = static_cast<const clang::TypedefType*>(T);
142      const clang::TypedefNameDecl *TD = TT->getDecl();
143      EI = GetElementInfo(TD->getName());
144      if (EI != NULL)
145        break;
146
147      T = TD->getUnderlyingType().getTypePtr();
148    }
149  }
150
151  if (EI == NULL) {
152    return RSExportType::Create(Context, T);
153  } else {
154    return RSExportElement::Create(Context, T, EI);
155  }
156}
157
158const RSExportElement::ElementInfo *
159RSExportElement::GetElementInfo(const llvm::StringRef &Name) {
160  if (!Initialized)
161    Init();
162
163  ElementInfoMapTy::const_iterator I = ElementInfoMap.find(Name);
164  if (I == ElementInfoMap.end())
165    return NULL;
166  else
167    return I->getValue();
168}
169
170}  // namespace slang
171