]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h
MFC r234353:
[FreeBSD/stable/9.git] / contrib / llvm / tools / clang / include / clang / StaticAnalyzer / Core / BugReporter / PathDiagnostic.h
1 //===--- PathDiagnostic.h - Path-Specific Diagnostic Handling ---*- 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 PathDiagnostic-related interfaces.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_CLANG_PATH_DIAGNOSTIC_H
15 #define LLVM_CLANG_PATH_DIAGNOSTIC_H
16
17 #include "clang/Basic/SourceLocation.h"
18 #include "clang/Analysis/ProgramPoint.h"
19 #include "llvm/ADT/FoldingSet.h"
20 #include "llvm/ADT/IntrusiveRefCntPtr.h"
21 #include "llvm/ADT/PointerUnion.h"
22 #include "llvm/ADT/Optional.h"
23 #include <deque>
24 #include <iterator>
25 #include <string>
26 #include <vector>
27
28 namespace clang {
29
30 class AnalysisDeclContext;
31 class BinaryOperator;
32 class CompoundStmt;
33 class Decl;
34 class LocationContext;
35 class MemberExpr;
36 class ParentMap;
37 class ProgramPoint;
38 class SourceManager;
39 class Stmt;
40
41 namespace ento {
42
43 class ExplodedNode;
44 class SymExpr;
45 typedef const SymExpr* SymbolRef;
46
47 //===----------------------------------------------------------------------===//
48 // High-level interface for handlers of path-sensitive diagnostics.
49 //===----------------------------------------------------------------------===//
50
51 class PathDiagnostic;
52
53 class PathDiagnosticConsumer {
54   virtual void anchor();
55 public:
56   PathDiagnosticConsumer() : flushed(false) {}
57   virtual ~PathDiagnosticConsumer();
58
59   void FlushDiagnostics(SmallVectorImpl<std::string> *FilesMade);
60
61   virtual void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags,
62                                     SmallVectorImpl<std::string> *FilesMade)
63                                     = 0;
64
65   virtual StringRef getName() const = 0;
66   
67   void HandlePathDiagnostic(PathDiagnostic *D);
68
69   enum PathGenerationScheme { Minimal, Extensive };
70   virtual PathGenerationScheme getGenerationScheme() const { return Minimal; }
71   virtual bool supportsLogicalOpControlFlow() const { return false; }
72   virtual bool supportsAllBlockEdges() const { return false; }
73   virtual bool useVerboseDescription() const { return true; }
74   
75   /// Return true if the PathDiagnosticConsumer supports individual
76   /// PathDiagnostics that span multiple files.
77   virtual bool supportsCrossFileDiagnostics() const { return false; }
78
79 protected:
80   bool flushed;
81   llvm::FoldingSet<PathDiagnostic> Diags;
82 };
83
84 //===----------------------------------------------------------------------===//
85 // Path-sensitive diagnostics.
86 //===----------------------------------------------------------------------===//
87
88 class PathDiagnosticRange : public SourceRange {
89 public:
90   bool isPoint;
91
92   PathDiagnosticRange(const SourceRange &R, bool isP = false)
93     : SourceRange(R), isPoint(isP) {}
94
95   PathDiagnosticRange() : isPoint(false) {}
96 };
97
98 typedef llvm::PointerUnion<const LocationContext*, AnalysisDeclContext*>
99                                                    LocationOrAnalysisDeclContext;
100
101 class PathDiagnosticLocation {
102 private:
103   enum Kind { RangeK, SingleLocK, StmtK, DeclK } K;
104   const Stmt *S;
105   const Decl *D;
106   const SourceManager *SM;
107   FullSourceLoc Loc;
108   PathDiagnosticRange Range;
109
110   PathDiagnosticLocation(SourceLocation L, const SourceManager &sm,
111                          Kind kind)
112     : K(kind), S(0), D(0), SM(&sm),
113       Loc(genLocation(L)), Range(genRange()) {
114     assert(Loc.isValid());
115     assert(Range.isValid());
116   }
117
118   FullSourceLoc
119     genLocation(SourceLocation L = SourceLocation(),
120                 LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const;
121
122   PathDiagnosticRange
123     genRange(LocationOrAnalysisDeclContext LAC = (AnalysisDeclContext*)0) const;
124
125 public:
126   /// Create an invalid location.
127   PathDiagnosticLocation()
128     : K(SingleLocK), S(0), D(0), SM(0) {}
129
130   /// Create a location corresponding to the given statement.
131   PathDiagnosticLocation(const Stmt *s,
132                          const SourceManager &sm,
133                          LocationOrAnalysisDeclContext lac)
134     : K(StmtK), S(s), D(0), SM(&sm),
135       Loc(genLocation(SourceLocation(), lac)),
136       Range(genRange(lac)) {
137     assert(S);
138     assert(Loc.isValid());
139     assert(Range.isValid());
140   }
141
142   /// Create a location corresponding to the given declaration.
143   PathDiagnosticLocation(const Decl *d, const SourceManager &sm)
144     : K(DeclK), S(0), D(d), SM(&sm),
145       Loc(genLocation()), Range(genRange()) {
146     assert(D);
147     assert(Loc.isValid());
148     assert(Range.isValid());
149   }
150
151   /// Create a location corresponding to the given declaration.
152   static PathDiagnosticLocation create(const Decl *D,
153                                        const SourceManager &SM) {
154     return PathDiagnosticLocation(D, SM);
155   }
156
157   /// Create a location for the beginning of the declaration.
158   static PathDiagnosticLocation createBegin(const Decl *D,
159                                             const SourceManager &SM);
160
161   /// Create a location for the beginning of the statement.
162   static PathDiagnosticLocation createBegin(const Stmt *S,
163                                             const SourceManager &SM,
164                                             const LocationOrAnalysisDeclContext LAC);
165
166   /// Create the location for the operator of the binary expression.
167   /// Assumes the statement has a valid location.
168   static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO,
169                                                   const SourceManager &SM);
170
171   /// For member expressions, return the location of the '.' or '->'.
172   /// Assumes the statement has a valid location.
173   static PathDiagnosticLocation createMemberLoc(const MemberExpr *ME,
174                                                 const SourceManager &SM);
175
176   /// Create a location for the beginning of the compound statement.
177   /// Assumes the statement has a valid location.
178   static PathDiagnosticLocation createBeginBrace(const CompoundStmt *CS,
179                                                  const SourceManager &SM);
180
181   /// Create a location for the end of the compound statement.
182   /// Assumes the statement has a valid location.
183   static PathDiagnosticLocation createEndBrace(const CompoundStmt *CS,
184                                                const SourceManager &SM);
185
186   /// Create a location for the beginning of the enclosing declaration body.
187   /// Defaults to the beginning of the first statement in the declaration body.
188   static PathDiagnosticLocation createDeclBegin(const LocationContext *LC,
189                                                 const SourceManager &SM);
190
191   /// Constructs a location for the end of the enclosing declaration body.
192   /// Defaults to the end of brace.
193   static PathDiagnosticLocation createDeclEnd(const LocationContext *LC,
194                                                    const SourceManager &SM);
195
196   /// Create a location corresponding to the given valid ExplodedNode.
197   static PathDiagnosticLocation create(const ProgramPoint& P,
198                                        const SourceManager &SMng);
199
200   /// Create a location corresponding to the next valid ExplodedNode as end
201   /// of path location.
202   static PathDiagnosticLocation createEndOfPath(const ExplodedNode* N,
203                                                 const SourceManager &SM);
204
205   /// Convert the given location into a single kind location.
206   static PathDiagnosticLocation createSingleLocation(
207                                              const PathDiagnosticLocation &PDL);
208
209   bool operator==(const PathDiagnosticLocation &X) const {
210     return K == X.K && Loc == X.Loc && Range == X.Range;
211   }
212
213   bool operator!=(const PathDiagnosticLocation &X) const {
214     return !(*this == X);
215   }
216
217   bool isValid() const {
218     return SM != 0;
219   }
220
221   FullSourceLoc asLocation() const {
222     return Loc;
223   }
224
225   PathDiagnosticRange asRange() const {
226     return Range;
227   }
228
229   const Stmt *asStmt() const { assert(isValid()); return S; }
230   const Decl *asDecl() const { assert(isValid()); return D; }
231
232   bool hasRange() const { return K == StmtK || K == RangeK || K == DeclK; }
233
234   void invalidate() {
235     *this = PathDiagnosticLocation();
236   }
237
238   void flatten();
239
240   const SourceManager& getManager() const { assert(isValid()); return *SM; }
241   
242   void Profile(llvm::FoldingSetNodeID &ID) const;
243 };
244
245 class PathDiagnosticLocationPair {
246 private:
247   PathDiagnosticLocation Start, End;
248 public:
249   PathDiagnosticLocationPair(const PathDiagnosticLocation &start,
250                              const PathDiagnosticLocation &end)
251     : Start(start), End(end) {}
252
253   const PathDiagnosticLocation &getStart() const { return Start; }
254   const PathDiagnosticLocation &getEnd() const { return End; }
255
256   void flatten() {
257     Start.flatten();
258     End.flatten();
259   }
260   
261   void Profile(llvm::FoldingSetNodeID &ID) const {
262     Start.Profile(ID);
263     End.Profile(ID);
264   }
265 };
266
267 //===----------------------------------------------------------------------===//
268 // Path "pieces" for path-sensitive diagnostics.
269 //===----------------------------------------------------------------------===//
270
271 class PathDiagnosticPiece : public RefCountedBaseVPTR {
272 public:
273   enum Kind { ControlFlow, Event, Macro, Call };
274   enum DisplayHint { Above, Below };
275
276 private:
277   const std::string str;
278   const Kind kind;
279   const DisplayHint Hint;
280   std::vector<SourceRange> ranges;
281
282   // Do not implement:
283   PathDiagnosticPiece();
284   PathDiagnosticPiece(const PathDiagnosticPiece &P);
285   PathDiagnosticPiece& operator=(const PathDiagnosticPiece &P);
286
287 protected:
288   PathDiagnosticPiece(StringRef s, Kind k, DisplayHint hint = Below);
289
290   PathDiagnosticPiece(Kind k, DisplayHint hint = Below);
291
292 public:
293   virtual ~PathDiagnosticPiece();
294
295   const std::string& getString() const { return str; }
296
297   /// getDisplayHint - Return a hint indicating where the diagnostic should
298   ///  be displayed by the PathDiagnosticConsumer.
299   DisplayHint getDisplayHint() const { return Hint; }
300
301   virtual PathDiagnosticLocation getLocation() const = 0;
302   virtual void flattenLocations() = 0;
303
304   Kind getKind() const { return kind; }
305
306   void addRange(SourceRange R) {
307     if (!R.isValid())
308       return;
309     ranges.push_back(R);
310   }
311
312   void addRange(SourceLocation B, SourceLocation E) {
313     if (!B.isValid() || !E.isValid())
314       return;
315     ranges.push_back(SourceRange(B,E));
316   }
317
318   typedef const SourceRange* range_iterator;
319
320   range_iterator ranges_begin() const {
321     return ranges.empty() ? NULL : &ranges[0];
322   }
323
324   range_iterator ranges_end() const {
325     return ranges_begin() + ranges.size();
326   }
327
328   static inline bool classof(const PathDiagnosticPiece *P) {
329     return true;
330   }
331   
332   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
333 };
334   
335   
336 class PathPieces :
337   public std::deque<IntrusiveRefCntPtr<PathDiagnosticPiece> > {
338 public:
339   ~PathPieces();  
340 };
341
342 class PathDiagnosticSpotPiece : public PathDiagnosticPiece {
343 private:
344   PathDiagnosticLocation Pos;
345 public:
346   PathDiagnosticSpotPiece(const PathDiagnosticLocation &pos,
347                           StringRef s,
348                           PathDiagnosticPiece::Kind k,
349                           bool addPosRange = true)
350   : PathDiagnosticPiece(s, k), Pos(pos) {
351     assert(Pos.isValid() && Pos.asLocation().isValid() &&
352            "PathDiagnosticSpotPiece's must have a valid location.");
353     if (addPosRange && Pos.hasRange()) addRange(Pos.asRange());
354   }
355
356   PathDiagnosticLocation getLocation() const { return Pos; }
357   virtual void flattenLocations() { Pos.flatten(); }
358   
359   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
360 };
361
362 /// \brief Interface for classes constructing Stack hints.
363 ///
364 /// If a PathDiagnosticEvent occurs in a different frame than the final 
365 /// diagnostic the hints can be used to summarise the effect of the call.
366 class StackHintGenerator {
367 public:
368   virtual ~StackHintGenerator() = 0;
369
370   /// \brief Construct the Diagnostic message for the given ExplodedNode.
371   virtual std::string getMessage(const ExplodedNode *N) = 0;
372 };
373
374 /// \brief Constructs a Stack hint for the given symbol.
375 ///
376 /// The class knows how to construct the stack hint message based on
377 /// traversing the CallExpr associated with the call and checking if the given
378 /// symbol is returned or is one of the arguments.
379 /// The hint can be customized by redefining 'getMessageForX()' methods.
380 class StackHintGeneratorForSymbol : public StackHintGenerator {
381 private:
382   SymbolRef Sym;
383   std::string Msg;
384
385 public:
386   StackHintGeneratorForSymbol(SymbolRef S, StringRef M) : Sym(S), Msg(M) {}
387   virtual ~StackHintGeneratorForSymbol() {}
388
389   /// \brief Search the call expression for the symbol Sym and dispatch the
390   /// 'getMessageForX()' methods to construct a specific message.
391   virtual std::string getMessage(const ExplodedNode *N);
392
393   /// Prints the ordinal form of the given integer,
394   /// only valid for ValNo : ValNo > 0.
395   void printOrdinal(unsigned ValNo, llvm::raw_svector_ostream &Out);
396
397   /// Produces the message of the following form:
398   ///   'Msg via Nth parameter'
399   virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex);
400   virtual std::string getMessageForReturn(const CallExpr *CallExpr) {
401     return Msg;
402   }
403   virtual std::string getMessageForSymbolNotFound() {
404     return Msg;
405   }
406 };
407
408 class PathDiagnosticEventPiece : public PathDiagnosticSpotPiece {
409   llvm::Optional<bool> IsPrunable;
410
411   /// If the event occurs in a different frame than the final diagnostic,
412   /// supply a message that will be used to construct an extra hint on the
413   /// returns from all the calls on the stack from this event to the final
414   /// diagnostic.
415   llvm::OwningPtr<StackHintGenerator> CallStackHint;
416
417 public:
418   PathDiagnosticEventPiece(const PathDiagnosticLocation &pos,
419                            StringRef s, bool addPosRange = true,
420                            StackHintGenerator *stackHint = 0)
421     : PathDiagnosticSpotPiece(pos, s, Event, addPosRange),
422       CallStackHint(stackHint) {}
423
424   ~PathDiagnosticEventPiece();
425
426   /// Mark the diagnostic piece as being potentially prunable.  This
427   /// flag may have been previously set, at which point it will not
428   /// be reset unless one specifies to do so.
429   void setPrunable(bool isPrunable, bool override = false) {
430     if (IsPrunable.hasValue() && !override)
431      return;
432     IsPrunable = isPrunable;
433   }
434
435   /// Return true if the diagnostic piece is prunable.
436   bool isPrunable() const {
437     return IsPrunable.hasValue() ? IsPrunable.getValue() : false;
438   }
439   
440   bool hasCallStackHint() {
441     return (CallStackHint != 0);
442   }
443
444   /// Produce the hint for the given node. The node contains 
445   /// information about the call for which the diagnostic can be generated.
446   std::string getCallStackMessage(const ExplodedNode *N) {
447     if (CallStackHint)
448       return CallStackHint->getMessage(N);
449     return "";  
450   }
451
452   static inline bool classof(const PathDiagnosticPiece *P) {
453     return P->getKind() == Event;
454   }
455 };
456
457 class PathDiagnosticCallPiece : public PathDiagnosticPiece {
458   PathDiagnosticCallPiece(const Decl *callerD,
459                           const PathDiagnosticLocation &callReturnPos)
460     : PathDiagnosticPiece(Call), Caller(callerD), Callee(0),
461       NoExit(false), callReturn(callReturnPos) {}
462
463   PathDiagnosticCallPiece(PathPieces &oldPath, const Decl *caller)
464     : PathDiagnosticPiece(Call), Caller(caller), Callee(0),
465       NoExit(true), path(oldPath) {}
466   
467   const Decl *Caller;
468   const Decl *Callee;
469
470   // Flag signifying that this diagnostic has only call enter and no matching
471   // call exit.
472   bool NoExit;
473
474   // The custom string, which should appear after the call Return Diagnostic.
475   // TODO: Should we allow multiple diagnostics?
476   std::string CallStackMessage;
477
478 public:
479   PathDiagnosticLocation callEnter;
480   PathDiagnosticLocation callEnterWithin;
481   PathDiagnosticLocation callReturn;  
482   PathPieces path;
483   
484   virtual ~PathDiagnosticCallPiece();
485   
486   const Decl *getCaller() const { return Caller; }
487   
488   const Decl *getCallee() const { return Callee; }
489   void setCallee(const CallEnter &CE, const SourceManager &SM);
490   
491   bool hasCallStackMessage() { return !CallStackMessage.empty(); }
492   void setCallStackMessage(StringRef st) {
493     CallStackMessage = st;
494   }
495
496   virtual PathDiagnosticLocation getLocation() const {
497     return callEnter;
498   }
499   
500   IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallEnterEvent() const;
501   IntrusiveRefCntPtr<PathDiagnosticEventPiece>
502     getCallEnterWithinCallerEvent() const;
503   IntrusiveRefCntPtr<PathDiagnosticEventPiece> getCallExitEvent() const;
504
505   virtual void flattenLocations() {
506     callEnter.flatten();
507     callReturn.flatten();
508     for (PathPieces::iterator I = path.begin(), 
509          E = path.end(); I != E; ++I) (*I)->flattenLocations();
510   }
511   
512   static PathDiagnosticCallPiece *construct(const ExplodedNode *N,
513                                             const CallExit &CE,
514                                             const SourceManager &SM);
515   
516   static PathDiagnosticCallPiece *construct(PathPieces &pieces,
517                                             const Decl *caller);
518   
519   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
520
521   static inline bool classof(const PathDiagnosticPiece *P) {
522     return P->getKind() == Call;
523   }
524 };
525
526 class PathDiagnosticControlFlowPiece : public PathDiagnosticPiece {
527   std::vector<PathDiagnosticLocationPair> LPairs;
528 public:
529   PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
530                                  const PathDiagnosticLocation &endPos,
531                                  StringRef s)
532     : PathDiagnosticPiece(s, ControlFlow) {
533       LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
534     }
535
536   PathDiagnosticControlFlowPiece(const PathDiagnosticLocation &startPos,
537                                  const PathDiagnosticLocation &endPos)
538     : PathDiagnosticPiece(ControlFlow) {
539       LPairs.push_back(PathDiagnosticLocationPair(startPos, endPos));
540     }
541
542   ~PathDiagnosticControlFlowPiece();
543
544   PathDiagnosticLocation getStartLocation() const {
545     assert(!LPairs.empty() &&
546            "PathDiagnosticControlFlowPiece needs at least one location.");
547     return LPairs[0].getStart();
548   }
549
550   PathDiagnosticLocation getEndLocation() const {
551     assert(!LPairs.empty() &&
552            "PathDiagnosticControlFlowPiece needs at least one location.");
553     return LPairs[0].getEnd();
554   }
555
556   void push_back(const PathDiagnosticLocationPair &X) { LPairs.push_back(X); }
557
558   virtual PathDiagnosticLocation getLocation() const {
559     return getStartLocation();
560   }
561
562   typedef std::vector<PathDiagnosticLocationPair>::iterator iterator;
563   iterator begin() { return LPairs.begin(); }
564   iterator end()   { return LPairs.end(); }
565
566   virtual void flattenLocations() {
567     for (iterator I=begin(), E=end(); I!=E; ++I) I->flatten();
568   }
569
570   typedef std::vector<PathDiagnosticLocationPair>::const_iterator
571           const_iterator;
572   const_iterator begin() const { return LPairs.begin(); }
573   const_iterator end() const   { return LPairs.end(); }
574
575   static inline bool classof(const PathDiagnosticPiece *P) {
576     return P->getKind() == ControlFlow;
577   }
578   
579   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
580 };
581
582 class PathDiagnosticMacroPiece : public PathDiagnosticSpotPiece {
583 public:
584   PathDiagnosticMacroPiece(const PathDiagnosticLocation &pos)
585     : PathDiagnosticSpotPiece(pos, "", Macro) {}
586
587   ~PathDiagnosticMacroPiece();
588
589   PathPieces subPieces;
590   
591   bool containsEvent() const;
592
593   virtual void flattenLocations() {
594     PathDiagnosticSpotPiece::flattenLocations();
595     for (PathPieces::iterator I = subPieces.begin(), 
596          E = subPieces.end(); I != E; ++I) (*I)->flattenLocations();
597   }
598
599   static inline bool classof(const PathDiagnosticPiece *P) {
600     return P->getKind() == Macro;
601   }
602   
603   virtual void Profile(llvm::FoldingSetNodeID &ID) const;
604 };
605
606 /// PathDiagnostic - PathDiagnostic objects represent a single path-sensitive
607 ///  diagnostic.  It represents an ordered-collection of PathDiagnosticPieces,
608 ///  each which represent the pieces of the path.
609 class PathDiagnostic : public llvm::FoldingSetNode {
610   const Decl *DeclWithIssue;
611   std::string BugType;
612   std::string Desc;
613   std::string Category;
614   std::deque<std::string> OtherDesc;
615   PathPieces pathImpl;
616   llvm::SmallVector<PathPieces *, 3> pathStack;
617   
618   PathDiagnostic(); // Do not implement.
619 public:
620   const PathPieces &path;
621
622   /// Return the path currently used by builders for constructing the 
623   /// PathDiagnostic.
624   PathPieces &getActivePath() {
625     if (pathStack.empty())
626       return pathImpl;
627     return *pathStack.back();
628   }
629   
630   /// Return a mutable version of 'path'.
631   PathPieces &getMutablePieces() {
632     return pathImpl;
633   }
634     
635   /// Return the unrolled size of the path.
636   unsigned full_size();
637
638   void pushActivePath(PathPieces *p) { pathStack.push_back(p); }
639   void popActivePath() { if (!pathStack.empty()) pathStack.pop_back(); }
640   
641   //  PathDiagnostic();
642   PathDiagnostic(const Decl *DeclWithIssue,
643                  StringRef bugtype,
644                  StringRef desc,
645                  StringRef category);
646
647   ~PathDiagnostic();
648
649   StringRef getDescription() const { return Desc; }
650   StringRef getBugType() const { return BugType; }
651   StringRef getCategory() const { return Category; }
652
653   /// Return the semantic context where an issue occurred.  If the
654   /// issue occurs along a path, this represents the "central" area
655   /// where the bug manifests.
656   const Decl *getDeclWithIssue() const { return DeclWithIssue; }
657
658   typedef std::deque<std::string>::const_iterator meta_iterator;
659   meta_iterator meta_begin() const { return OtherDesc.begin(); }
660   meta_iterator meta_end() const { return OtherDesc.end(); }
661   void addMeta(StringRef s) { OtherDesc.push_back(s); }
662
663   PathDiagnosticLocation getLocation() const;
664
665   void flattenLocations() {
666     for (PathPieces::iterator I = pathImpl.begin(), E = pathImpl.end(); 
667          I != E; ++I) (*I)->flattenLocations();
668   }
669   
670   void Profile(llvm::FoldingSetNodeID &ID) const;
671   
672   void FullProfile(llvm::FoldingSetNodeID &ID) const;
673 };  
674
675 } // end GR namespace
676
677 } //end clang namespace
678
679 #endif