]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp
Merge ACPICA 20110112. Switch to BSD/GPLv2 dual license[1].
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / AST / ASTDiagnostic.cpp
1 //===--- ASTDiagnostic.cpp - Diagnostic Printing Hooks for AST Nodes ------===//
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 implements a diagnostic formatting hook for AST elements.
11 //
12 //===----------------------------------------------------------------------===//
13 #include "clang/AST/ASTDiagnostic.h"
14
15 #include "clang/AST/ASTContext.h"
16 #include "clang/AST/DeclObjC.h"
17 #include "clang/AST/Type.h"
18 #include "llvm/Support/raw_ostream.h"
19
20 using namespace clang;
21
22 // Returns a desugared version of the QualType, and marks ShouldAKA as true
23 // whenever we remove significant sugar from the type.
24 static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
25   QualifierCollector QC;
26
27   while (true) {
28     const Type *Ty = QC.strip(QT);
29
30     // Don't aka just because we saw an elaborated type...
31     if (isa<ElaboratedType>(Ty)) {
32       QT = cast<ElaboratedType>(Ty)->desugar();
33       continue;
34     }
35
36     // ...or a substituted template type parameter.
37     if (isa<SubstTemplateTypeParmType>(Ty)) {
38       QT = cast<SubstTemplateTypeParmType>(Ty)->desugar();
39       continue;
40     }
41
42     // Don't desugar template specializations. 
43     if (isa<TemplateSpecializationType>(Ty))
44       break;
45
46     // Don't desugar magic Objective-C types.
47     if (QualType(Ty,0) == Context.getObjCIdType() ||
48         QualType(Ty,0) == Context.getObjCClassType() ||
49         QualType(Ty,0) == Context.getObjCSelType() ||
50         QualType(Ty,0) == Context.getObjCProtoType())
51       break;
52
53     // Don't desugar va_list.
54     if (QualType(Ty,0) == Context.getBuiltinVaListType())
55       break;
56
57     // Otherwise, do a single-step desugar.
58     QualType Underlying;
59     bool IsSugar = false;
60     switch (Ty->getTypeClass()) {
61 #define ABSTRACT_TYPE(Class, Base)
62 #define TYPE(Class, Base) \
63 case Type::Class: { \
64 const Class##Type *CTy = cast<Class##Type>(Ty); \
65 if (CTy->isSugared()) { \
66 IsSugar = true; \
67 Underlying = CTy->desugar(); \
68 } \
69 break; \
70 }
71 #include "clang/AST/TypeNodes.def"
72     }
73
74     // If it wasn't sugared, we're done.
75     if (!IsSugar)
76       break;
77
78     // If the desugared type is a vector type, we don't want to expand
79     // it, it will turn into an attribute mess. People want their "vec4".
80     if (isa<VectorType>(Underlying))
81       break;
82
83     // Don't desugar through the primary typedef of an anonymous type.
84     if (isa<TagType>(Underlying) && isa<TypedefType>(QT))
85       if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() ==
86           cast<TypedefType>(QT)->getDecl())
87         break;
88
89     // Record that we actually looked through an opaque type here.
90     ShouldAKA = true;
91     QT = Underlying;
92   }
93
94   // If we have a pointer-like type, desugar the pointee as well.
95   // FIXME: Handle other pointer-like types.
96   if (const PointerType *Ty = QT->getAs<PointerType>()) {
97       QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(),
98                                           ShouldAKA));
99   } else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) {
100       QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(),
101                                                   ShouldAKA));
102   }
103
104   return QC.apply(QT);
105 }
106
107 /// \brief Convert the given type to a string suitable for printing as part of 
108 /// a diagnostic.
109 ///
110 /// There are three main criteria when determining whether we should have an
111 /// a.k.a. clause when pretty-printing a type:
112 ///
113 /// 1) Some types provide very minimal sugar that doesn't impede the
114 ///    user's understanding --- for example, elaborated type
115 ///    specifiers.  If this is all the sugar we see, we don't want an
116 ///    a.k.a. clause.
117 /// 2) Some types are technically sugared but are much more familiar
118 ///    when seen in their sugared form --- for example, va_list,
119 ///    vector types, and the magic Objective C types.  We don't
120 ///    want to desugar these, even if we do produce an a.k.a. clause.
121 /// 3) Some types may have already been desugared previously in this diagnostic.
122 ///    if this is the case, doing another "aka" would just be clutter.
123 ///
124 /// \param Context the context in which the type was allocated
125 /// \param Ty the type to print
126 static std::string
127 ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty,
128                               const Diagnostic::ArgumentValue *PrevArgs,
129                               unsigned NumPrevArgs) {
130   // FIXME: Playing with std::string is really slow.
131   std::string S = Ty.getAsString(Context.PrintingPolicy);
132
133   // Check to see if we already desugared this type in this
134   // diagnostic.  If so, don't do it again.
135   bool Repeated = false;
136   for (unsigned i = 0; i != NumPrevArgs; ++i) {
137     // TODO: Handle ak_declcontext case.
138     if (PrevArgs[i].first == Diagnostic::ak_qualtype) {
139       void *Ptr = (void*)PrevArgs[i].second;
140       QualType PrevTy(QualType::getFromOpaquePtr(Ptr));
141       if (PrevTy == Ty) {
142         Repeated = true;
143         break;
144       }
145     }
146   }
147
148   // Consider producing an a.k.a. clause if removing all the direct
149   // sugar gives us something "significantly different".
150   if (!Repeated) {
151     bool ShouldAKA = false;
152     QualType DesugaredTy = Desugar(Context, Ty, ShouldAKA);
153     if (ShouldAKA) {
154       std::string D = DesugaredTy.getAsString(Context.PrintingPolicy);
155       if (D != S) {
156         S = "'" + S + "' (aka '";
157         S += D;
158         S += "')";
159         return S;
160       }
161     }
162   }
163
164   S = "'" + S + "'";
165   return S;
166 }
167
168 void clang::FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind, 
169                                             intptr_t Val,
170                                             const char *Modifier, 
171                                             unsigned ModLen,
172                                             const char *Argument, 
173                                             unsigned ArgLen,
174                                     const Diagnostic::ArgumentValue *PrevArgs,
175                                             unsigned NumPrevArgs,
176                                             llvm::SmallVectorImpl<char> &Output,
177                                             void *Cookie) {
178   ASTContext &Context = *static_cast<ASTContext*>(Cookie);
179   
180   std::string S;
181   bool NeedQuotes = true;
182   
183   switch (Kind) {
184     default: assert(0 && "unknown ArgumentKind");
185     case Diagnostic::ak_qualtype: {
186       assert(ModLen == 0 && ArgLen == 0 &&
187              "Invalid modifier for QualType argument");
188       
189       QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
190       S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs);
191       NeedQuotes = false;
192       break;
193     }
194     case Diagnostic::ak_declarationname: {
195       DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
196       S = N.getAsString();
197       
198       if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0)
199         S = '+' + S;
200       else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12)
201                 && ArgLen==0)
202         S = '-' + S;
203       else
204         assert(ModLen == 0 && ArgLen == 0 &&
205                "Invalid modifier for DeclarationName argument");
206       break;
207     }
208     case Diagnostic::ak_nameddecl: {
209       bool Qualified;
210       if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
211         Qualified = true;
212       else {
213         assert(ModLen == 0 && ArgLen == 0 &&
214                "Invalid modifier for NamedDecl* argument");
215         Qualified = false;
216       }
217       reinterpret_cast<NamedDecl*>(Val)->
218       getNameForDiagnostic(S, Context.PrintingPolicy, Qualified);
219       break;
220     }
221     case Diagnostic::ak_nestednamespec: {
222       llvm::raw_string_ostream OS(S);
223       reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS,
224                                                         Context.PrintingPolicy);
225       NeedQuotes = false;
226       break;
227     }
228     case Diagnostic::ak_declcontext: {
229       DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
230       assert(DC && "Should never have a null declaration context");
231       
232       if (DC->isTranslationUnit()) {
233         // FIXME: Get these strings from some localized place
234         if (Context.getLangOptions().CPlusPlus)
235           S = "the global namespace";
236         else
237           S = "the global scope";
238       } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
239         S = ConvertTypeToDiagnosticString(Context, 
240                                           Context.getTypeDeclType(Type),
241                                           PrevArgs, NumPrevArgs);
242       } else {
243         // FIXME: Get these strings from some localized place
244         NamedDecl *ND = cast<NamedDecl>(DC);
245         if (isa<NamespaceDecl>(ND))
246           S += "namespace ";
247         else if (isa<ObjCMethodDecl>(ND))
248           S += "method ";
249         else if (isa<FunctionDecl>(ND))
250           S += "function ";
251         
252         S += "'";
253         ND->getNameForDiagnostic(S, Context.PrintingPolicy, true);
254         S += "'";
255       }
256       NeedQuotes = false;
257       break;
258     }
259   }
260   
261   if (NeedQuotes)
262     Output.push_back('\'');
263   
264   Output.append(S.begin(), S.end());
265   
266   if (NeedQuotes)
267     Output.push_back('\'');
268 }